韵律定义词的正则表达式:在 Atom 中工作但在 grep 中不工作

Regex for prosodically-defined words: working in Atom but not grep

我正在尝试在 .txt 词典中搜索所有三音节词根,然后将匹配的词根传递到新的 .txt 文件。有问题的词典是 Heath 的 Nunggubuyu 词典的原始文本版本。当我在 Atom(我喜欢的文本编辑器)中搜索文件时,以下字符串可以很好地挑选出所需的词根并从词条(以空格开头)下方的定义中删除任何 material,如以及任何英语单词,以及任何被连字符或等号打断的三音节字符串(这意味着它们不是单词根)。如果它看起来笨重,请原谅我;我是一个绝对的初学者。 (本正字法中元音长度用':'表示,只有三个元音'a,i,u'。None词条大写。)

^\S[^aeiousf]*[aiu:]+[^csfaioeu:\-\=\W]+[aiu:]+[^VNcsfaeiou:\-\=]+[aiu:]+[^VcsfNaeiou:]*\b

但是,我需要将匹配的字符串输出到一个新文件中。当我尝试在 grep 中使用相同的字符串时(在 Mac 上),没有任何匹配项。我使用语法

grep -o "^\S[^aeiousf]*[aiu:]+[^csfaioeu:\-\=\W]+[aiu:]+[^VNcsfaeiou:\-\=]+[aiu:]+[^VcsfNaeiou:]*\b" Dict-nofrontmatter.txt > output.txt

我已经搜索了几个小时,试图弄清楚如何将 Atom 的正则表达式方言转换为 grep (Mac),但无济于事。每当我设法获得匹配项时,结果看起来与我的预期以及我从 Atom 获得的结果大不相同。我也看过一些明显的 Atom grep 工具,但文档几乎不存在,所以我什至无法弄清楚它们的作用。我在这里弄错了什么?我应该尝试使用 grep 的替代方法吗?

grep 支持不同的正则表达式样式。来自 man re_format:

Regular expressions ("RE"s), as defined in POSIX.2, come in two forms:
modern REs (roughly those of egrep; POSIX.2 calls these extended REs) and
obsolete REs (roughly those of ed(1); POSIX.2 basic REs).

Grep 有开关来选择使用哪个变体。功能从少到多排序:

固定字符串: grep -Ffgrep
根本没有正则表达式。纯文本搜索。

基本正则表达式: grep -Ggrep
|+?是普通字符。 | 没有等价物。必须转义括号才能用作子表达式。

扩展正则表达式: grep -Eegrep
"Normal" 正则表达式 |+? bounds 等等。

perl 正则表达式: grep -P(用于 GNU grep,未预装在 Mac 上)
最强大的正则表达式。支持前瞻和其他功能。

在你的情况下,你应该尝试 grep -Eo "^\S...

可能您的 grep 命令中唯一缺少的是 -E 选项:

regex='^\S[^aeiousf]*[aiu:]+[^csfaioeu:\-\=\W]+[aiu:]+[^VNcsfaeiou:\-\=]+[aiu:]+[^VcsfNaeiou:]*\b'
grep -Eo "$regex" Dict-nofrontmatter.txt > output.txt

-E 激活对 extended(现代)正则表达式的支持,现在可以正常工作(重复符号 +?按预期工作,() 形成捕获组,| 交替)。

没有-E(或有-Gbasic假定正则表达式——一种语法不同的有限遗留形式。鉴于-E is part of POSIX,没有理由使用它。

在 macOS 上,grep 理解字符-class 快捷方式,例如 \S\W,以及单词- 边界断言,例如 \b - 这与 macOS 附带的其他 BSD 实用程序形成对比,特别是 sedawk.


看起来你不需要它,但是 PRCEs (Perl-compatible Regular Expressions) would provide additional features, such as look-around assertions

macOS grep 不支持它们,但是 GNU grep 通过 -P 选项支持。您可以通过 Homebrew.

在 macOS 上安装 GNU grep

或者,您可以直接使用 perl;与上述命令等效的是:

regex='^\S[^aeiousf]*[aiu:]+[^csfaioeu:\-\=\W]+[aiu:]+[^VNcsfaeiou:\-\=]+[aiu:]+[^VcsfNaeiou:]*\b'
perl -lne "print for m/$regex/g" Dict-nofrontmatter.txt > output.txt