我正在尝试编写一个egrep脚本来区分一组txt文件中的名称(首字母大写的单词,例如国家/地区、人名等)。我想忽略数字并选择所有大写单词,仅选择单词,不包括句子开头的单词(因此,在“.”之后)也欢迎其他推荐模式
输入示例可以是:
自 1800 年代以来,公众一直对火星上是否有水感兴趣。 1877 年,当火星几乎尽可能接近地球时(距离地球仍然相当遥远,有 5600 万公里),意大利天文学家乔瓦尼·夏帕雷利 (Giovanni Schiaparelli) 观测到了这颗红色星球。他绘制了他所看到的表面特征的地图,包括看起来像渠道网络的东西。
输出将是:
Earth
Giovanni
Italian
Mars
Planet
Red
Schiparelli
答案1
一种方法是 i) 删除所有换行符,以便整个字符串是一个长字符串,并且您可以避免匹配其前面的句号位于上一行的句子的第一个单词,并且 ii) 找到其第一个字母的所有单词是大写且其前面的字符不是.
, ?
,之一!
。例如:
$ tr '\n' ' ' < file | grep -Po '(?<![.!?]) \K[A-Z]\w+'
Mars
Mars
Earth
Italian
Giovanni
Schiaparelli
Red
Planet
并删除重复的条目:
$ tr '\n' ' ' < file | grep -Po '(?<![.!?]) \K[A-Z]\w+' | sort -u
Earth
Giovanni
Italian
Mars
Planet
Red
Schiaparelli
tr
用空格替换换行符。该-P
开关打开 Perl 兼容正则表达式 (PCRE) 支持,为我们提供了正在使用的高级功能。意思-o
是“仅打印该行的匹配部分”。
正则表达式使用消极回顾( (?>!foo)
) 以确保我们只匹配除?
、!
或.
、空格、大写字母[A-Z]
和一个或多个单词字符之外的任何内容。
请注意,如果出现以下情况,这将失败:
- 名称是文件的第一个单词;
- 名字是句子的第一个单词;
- 如果您有像 María de Quinto 这样的复合名称,它将匹配
María
但Quinto
会跳过de
.
如果您grep
不支持-P
或-o
选项,您可以使用 Perl 代替:
perl -0lne 'print join "\n",(/(?<![.!?]) \K[A-Z]\w+/g)' file | sort -u