Wie kann man "grep -w" sagen, welche Zeichen "Wörter" bilden?

7
$ printf 'asf .test. afd\nasaf foo-test asfdads\n'
asf .test. afd
asaf foo-test asfdads

$ printf 'asf .test. afd\nasaf foo-test asfdads\n' | grep -w test
asf .test. afd
asaf foo-test asfdads

Frage : Wie kann ich den "foo-Test" abgleichen? Genauer gesagt, wie kann ich sagen, dass "-w" "-" als Trennzeichen verwendet, aber nicht "." ?

Oder mit anderen Worten, kann ich sagen, grepdass dies .zu den Zeichen gehört, aus denen Wörter bestehen , und dass es daher keine Wortgrenze zwischen .und gibt test?

Oder gibt es andere Lösungen als grep?

verdammt gute Frage
quelle
Wie können Sie den "foo-Test" abgleichen? grep für "foo-test"? Ich bin mir ziemlich sicher, dass ich Ihre Frage nicht verstehe.
Celada
Ich habe die Frage aktualisiert.
Freaking-Good-Frage
Aber beide .und -sind bereits Trennzeichen: von der Manpage: "Wortbestandteile sind Buchstaben, Ziffern und der Unterstrich."
Celada
Wie kann ich sagen, dass "-w" "-" als Trennzeichen verwendet, aber nicht "."?
Freaking-Good-Frage
Ja, und die Lösung muss nicht in grep sein
verdammt gute Frage

Antworten:

10

In Versionen vor 2.19, GNU grep‚s -wwürde nur Ein-Byte - Zeichen alnums und Unterstrich (so in UTF-8 - Sprachumgebungen, werden nur die 26 + 26 + 10 + 1 (ASCII Buchstaben, Ziffern und den Unterstrich)) betrachtet als Wortbestandteile. So würde zum Beispiel echo Stéphane | grep -w Stübereinstimmen. Das wurde in 2.19 behoben.

Sie können die Logik jedoch von Hand implementieren:

 grep -E '([^[:alnum:]_.]|^)test([^[:alnum:]_.]|$)'

Dies wird testentweder durch einen Nicht-Wort-Bestandteil oder den Anfang der Zeile und gefolgt von entweder einem nicht-Wort-Bestandteil oder dem Ende der Zeile voraus.

(oben [:alnum:]stimmen Ziffern und Buchstaben in Ihrem Gebietsschema überein, nicht nur ASCII-Ziffern. Korrigieren Sie das Gebietsschema auf C, wenn Sie nur ASCII-Ziffern möchten.)

Wenn Sie nicht möchten, dass die umgebenden Nicht-Wortbestandteile in die Übereinstimmung einbezogen werden (z. B. weil Sie GNUs verwenden -o), können Sie diesmal PCRE-Regexps und Look-Around-Operatoren verwenden:

grep -Po '(*UCP)(?<![\w.])test(?![\w.])'

Entfernen (*UCP)und hinzufügen LC_ALL=C, damit nur ASCII-Buchstaben und -Ziffern übereinstimmen.

Die Verwendung (*UCP)zu Beginn eines regulären Ausdrucks teilt der PCRE-Bibliothek mit, dass U̲niC̲ode-Eigenschaften verwendet werden müssen \w.

Ohne \wwürde es mit den alphanumerischen Zeichen und dem Unterstrich Ihres Gebietsschemas übereinstimmen, jedoch nur für Einzelbyte-Zeichen. Das würde in UTF-8-Gebietsschemas (heutzutage die Norm) nicht funktionieren, in denen nur ASCII-Gebietsschemas übereinstimmen würden. (*UCP)Damit funktioniert es auch für UTF-8. Es würde auf der Grundlage von PCREs eigener Vorstellung von Zeicheneigenschaften übereinstimmen, die sich möglicherweise von denen Ihres Gebietsschemas unterscheiden, aber auf GNU-Systemen ist dies genauso gut wie die dortigen UTF-8-Gebietsschemadefinitionen, die unvollständig und veraltet sind (zumindest ab 2015-04).

Stéphane Chazelas
quelle