一条线上正好两个大写的单词

时间:2017-12-13 11:01:39

标签: regex ubuntu sed

我想创建一个正则表达式,它可以替换包含两个单词的行,这两个单词以大写字母“X”开头。

我目前正在使用它:

sed -e '/\b[A-Z][a-z]*\b c X /home/Morgan/desktop/test

问题如下:它只更改包含我test.txt中正则表达式所描述的1个或多个单词的行。

我不知道怎么说我只想要一个只有2个以大写字母开头的行的X.这两个词都可以出现在该行的任何地方。

我的test.txt包含:

  

Bonjour oui oui Bonjour - >这必须由X

代替      

Bonjour Bonjour Bonjour - >这一定不能

     

Bonjour Oui bonjour oui - >这必须由X

代替

1 个答案:

答案 0 :(得分:3)

您似乎尝试使用Perl / PCRE字边界\b,但典型的sed实现不理解这种正则表达式方言。通过你的问题描述,无论如何,你正在寻找线的起点和终点;这是一个非常基本的正则表达式锚点,已在原始grep中引入:^匹配行的开头,$匹配行尾。

没有锚点,正则表达式将匹配行中的任何位置。要说“只有两个”你真的必须检查整行,并确保没有三个或更多你正在寻找。

“找到一行只包含两个以大写字母开头的单词”需要重新编写或按摩一下才能尝试编写正则表达式。如果我们 - 暂时,在本次讨论中 - 将w定义为“不以大写字母开头的单词”,将W定义为表示您需要的单词^w*Ww*Ww*$两个大写单词,在它们之前,之间或之后的任何位置都有零个或多个非大写单词。

以大写字母开头的单词是[A-Z][a-z]*(这需要所有后续字符都是小写),而单词不是[a-z][a-z]*(或[a-z]\+如果你的{sed 1}}支持正则表达式变体)。

因为单词之间需要空格,所以需要将可选的单词表达式括起来,这样就可以说“整个序列中的零个或多个”。通常,sed正则表达式也要求对括号进行反序分组,尽管版本之间存在差异。

所以,试试这个:

sed 's/^\([a-z][a-z]* \)*[A-Z][a-z]*\( [a-z][a-z]*\)* [A-Z][a-z]*\( [a-z][a-z]*\)*$/X/' file

如果您确实拥有GNU sed,可以稍微简化一下:

sed -r 's/^([a-z]+ )*[A-Z][a-z]*( [a-z]+)* [A-Z][a-z]*( [a-z]+)*$/X/' file

这个“单词”的定义可能还不够;也许你可以根据自己的情况改进它。特别是,假设间距是规则的(单词之间恰好有一个空格;行上没有前导或尾随空格),并且没有文本可能包含空格外的字符和大写或小写字母a-z。 (è和Á等重音字符在此范围内也被视为字母,取决于您的语言环境设置。如果法语区域设置很重要,可以在脚本中设置LC_ALL=fr_FR.utf-8。)

另请注意sed替换命令如何只需要三个分隔符 - 传统上,我们使用斜杠,但您可以使用任何标点字符。表单为s/regex/replacement/flags,其中正则表达式,替换符和标志都可以为空,但始终需要s和分隔符。