L’objective est d’extraire les mêmes lignes à partir de deux fichiers sans tenir compte des majuscules / minuscules et sans tenir compte des ponctuations
J’ai deux fichiers
source.txt
Foo bar blah blah black sheep Hello World Kick the, bucket
processed.txt
foo bar blah sheep black Hello world kick the bucket ,
Sortie souhaitée (à partir de source.txt
):
Foo bar Hello World Kick the, bucket
Je l’ai fait en tant que tel:
from ssortingng import punctuation with open('source.txt', 'r') as f1, open('processed.txt', 'r') as f2: for i,j in zip(f1, f2): lower_depunct_f1 = " ".join("".join([ch.lower() for ch in f1 if f1 not in punctuation]).split()) lower_depunct_f2 = " ".join("".join([ch.lower() for ch in f2 if f2 not in punctuation]).split()) if lower_depunct_f1 == lower_depunct_f2: print f1 else: print
Est-il possible de faire cela avec les outils bash
? perl, shell, awk, sed?
Plus facile à faire en utilisant awk
:
awk 'FNR==NR {s=toupper($0); gsub(/[[:blank:][:punct:]]+/, "", s); a[s]++;next} {s=toupper($0); gsub(/[[:blank:][:punct:]]+/, "", s); print (s in a)?$0:""}' file2 file1 Foo bar Hello World Kick the, bucket
La solution Perl est assez similaire à celle de Python:
open my $S1, '<', 'source.txt' or die $!; open my $S2, '<', 'processed.txt' or die $!; while (defined(my $s1 = <$S1>) and defined (my $s2 = <$S2>)) { s/[[:punct:]]//g for $s1, $s2; $_ = lc for $s1, $s2; print $s1 eq $s2 ? $s1 : "\n"; }
Notez que le résultat est différent du vôtre, car l’espace après le kick the bucket
de kick the bucket
n’a pas été supprimé.
Solution Bash, tout à fait identique à celle de Perl, avec le même résultat différent (car l’espace après le kick the bucket
n’a pas été supprimé):
#!/bin/bash shopt -s nocasematch exec 3<> source.txt # Open source.txt and assign fd 3 to it. exec 4<> processed.txt while read <&3 varline && read <&4 varpro do varline_noPunct=`echo $varline | tr -d '[:punct:]'` varpro_noPunct=`echo $varpro | tr -d '[:punct:]'` [[ $varline_noPunct == $varpro_noPunct ]] && echo "$varline" || echo done exec 3>&- # Close fd 3. exec 4>&-
Vérifiez si cette solution vous aide à:
use ssortingct; use warnings; my $f1 = $ARGV[0]; open FILE1, "<", $f1 or die $!; my $f2 = $ARGV[1]; open FILE2, "<", $f2 or die $!; open OUTFILE, ">", "cmp.txt" or die $!; my %seen; while () { $_ =~ s/[[:punct:]]//isg; $seen{lc($_)} = 1; } while () { my $next_line = ; $_ =~ s/[[:punct:]]//isg; if ($seen{lc($_)}) { print OUTFILE $_; } } close OUTFILE;