2016-06-08 11 views
1

Ich habe das folgende Problem, ich muss alle Wörter abrufen, die genau 2 Vokale (in beliebiger Reihenfolge) aus einer Datei enthält. Die Datei enthält nur ein Wort pro Zeile.Grep Worte mit genau zwei Vokalen

Meine aktuelle Problemumgehung ist:

Grep1: Wörter abrufen wie earth, over, under, one...

grep -i "^[aeiou][^aeiou]*[aeiou][^aeiou]*$" genesis.words > A.txt 

und

Grep2: Wörter abrufen wie formless, deep, said...

grep -i "^[^aeiou][^aeiou]*[aeiou][^aeiou]*[aeiou][^aeiou]*$" genesis.words > B.txt 

die obige Lösung funktioniert, aber wenn ich beide Regex in eine einzige Regex verketten dann nichts zurück!

Mutter von Grep1 & Grep2: sollte alles abrufen!

grep -i "^[aeiou][^aeiou]*[aeiou][^aeiou]*$|^[^aeiou][^aeiou]*[aeiou][^aeiou]*[aeiou][^aeiou]*$" genesis.words 

Ich denke, Ausgabe um meine Implementierung von ^$ in Ausdruck ist aber noch ohne Erfolg diff Versionen ausprobiert!

Jede Hilfe wird sehr geschätzt!

OS ist AIX 6100-09-04-1441

Antwort

1

Sie waren in der Nähe Dies sollte funktionieren:

grep -i "^[^aeiou]*[aeiou][^aeiou]*[aeiou][^aeiou]*$" genesis.words > A.txt 

So sollte es alle acht Möglichkeiten finden (zwei Vokale drei nonvowel Sequenz identifizieren, die jeweils möglicherweise leer; 2^3 ist 8).

 [ ]I[ ]o[ ] 
    [ ]e[ ]a[r] 
    [ ]e[r]a[ ] 
    [ ]e[l]a[n] 
    [T]e[ ]a[ ] 
    [D]e[ ]a[r] 
    [D]e[w]a[r] 
    [D]a[w]a[ ] 
    [H]a[w]a[y] 

Wie bei der Verkettung, | muss entkommen.Sie können eine einzelne Verankerung verwenden:

^(regexp1\|regexp2)$ 
+0

danke! Ihre Lösung wirkt wie ein Zauber! Was die Verkettung anbetrifft, habe ich Ihren Vorschlag angewandt, aber nichts zurückgegeben. – Altons

1

Da die * 0 mal mithalten können oder mehr sollten Sie in der Lage sein, um die Zeichenfolge mit [^aeiou]* zu starten: Wie

"^[^aeiou]*[aeiou][^aeiou]*[aeiou][^aeiou]*$" 

versuchen für die Befestigung Ihrer regex, ich glaube, Sie brauchen die Bar als \| zu entkommen, so

grep -i "^[aeiou][^aeiou]*[aeiou][^aeiou]*$\|^[^aeiou][^aeiou]*[aeiou][^aeiou]*[aeiou][^aeiou]*$" genesis.words 
1

Wenn Sie nichts dagegen nicht Perl, Sie Dies könnte verwendet werden:

perl -lne '$m=$_; tr/[aeiou]//cd; print $m if length()==2;' /usr/share/dict/words 

Das sagt ... „die aktuelle Zeile speichern (Wort) in $ m. Lösche alles, was kein Vokal ist. Drucken Sie das ursprüngliche Wort, wenn es zwei Dinge (zB Vokale) links.“

Bitte beachte, dass ich bin mit dem Systemwörterbuch als Input für meine Tests.

Sie können so ziemlich die gleiche Sache in awk tun.

+0

Dies zeigt, warum 'Perl' manchmal eine so tolle Sprache ist! +1 Du hast "awk" erwähnt, obwohl es einen Vorteil hat, einen über den anderen zu benutzen? –

+1

Ich denke, für mich ist der Vorteil von Perl, dass es unter Linux, Unix, OSX und Windows genau gleich ist - nur eine Standardregexsyntax, nur eine konsistente Dateinamenskonvention, eine standardisierte Menge von Zeilenenden, eine Escape-Set, nur eine Datumssyntax, nur eine "Find" -Syntax, es macht alles, was 'tr' kann,' sed', alles was 'awk' kann,' grep', 'fgrep', CPAN ... –

1

Wenn Sie in der Lage sind, eine Alternative zu verwenden tr mit wc grep funktioniert gut:

words=/path/to/words.txt 

while read -e word ; do 
    v=$(echo $word | tr -cd 'aeiou' | wc -c) 
    [[ ! $v -eq "2" ]] || echo $word >> output.txt 
done < $words 

Dieser liest die ursprüngliche Datei Zeile für Zeile, zählt die Vokale & gibt Ergebnisse mit nur 2 an output.txt zurück.

+0

Danke für Diff-Ansatz - habe nicht so gedacht, aber da dies normalerweise von der Befehlszeile (schnell & schmutzig) ausgeführt wird, grep wäre die beste Option in diesem speziellen Fall. – Altons