sed与正则表达式不匹配

时间:2016-03-09 08:39:50

标签: regex bash sed

我写了this正则表达式:

text = "#{value1} has viewed your" '"' "#{value2}" '"'

我想在我的终端上用

测试它
/_([^_+\n][\w]+)_/g

然而,它输出

echo "HELLO ___ _HELO_WORLD_" | sed "/_([^_+\n][\w]+)_/g"

这意味着sed与任何东西都不匹配。

结果必须是:

HELLO ___ _HELO_WORLD_

我正在使用OS X,我按照其他帖子的建议尝试了_HELLO_WORLD_ -E,但这并没有改变任何内容。我在这里做错了什么?

4 个答案:

答案 0 :(得分:1)

sed并不特别适合这项任务,因为它非常适合将模式应用于行,而不是单词,使正则表达式过于复杂。

面向单词的解决方案

无论如何,这是一次尝试,使用两种替换模式:

sed -e 's|\<[^_][^\> ]*[^_]\> *||g' -e 's|\<_*\> *||g'

第一个表达式替换任何既不以下划线开头也不以任何尾随空格结尾的单词。 \<表示单词的开头,\>表示结尾;因此\<\([^_][^\>]*[^_]\)\>转换为&#34;在开始时\<没有下划线[^_],后跟任何数字的字符[^\>]都没有结尾。在单词结束[^_]

之前,后跟一个不是下划线\>的字符

第二个表达式更简单,并且替换任何仅由下划线组成的单词。

面向行的处理

如果您可以安排数据为每行一个表达式,则可以使用以下内容

$ cat data.txt
HELLO
___
_HELO_WORLD_
$ cat data.txt | sed -n -e '/_[^_+\s]\w*_/p'
_HELO_WORLD_
$

sed-term几乎就是你给出的那个(虽然由于某些原因sed不喜欢+,所以我使用*代替。< / p>

基本技巧是使用-n标志禁用默认打印行,并使用p命令明确打印匹配行。

答案 1 :(得分:0)

我仍然不确定你在问什么,所以我回答我猜你在问什么。我的猜测是,你想要找到用Sed下划线包围的字符串。最简洁的答案是不。时间越长:您无法找到与Sed重叠的字符串部分,因为它不支持lookahead

如果您使用此字符串_HELLO_WORLD_和以下模式_[^_]*_,则模式将匹配_HELLO_,其余字符串为WORLD_,这将不匹配,因为领先的下划线已被消费。

Sed是错误的工具。请改用Perl。这将打印由下划线包围的所有字符串:

$ echo "HELLO ___ _HELO_WORLD_" | perl -ne 's/_([A-Z]+)(?=_)/print $1/ge'
HELOWORLD

更新反映您的上一条评论:

如果您想在word boundaries找到以下划线开头和结尾的字符串,请使用以下字符串:

$ echo "HELLO ___ _HELO_WORLD_" | perl -ne 's/\b_([A-Z]+[_A-Z]*[A-Z]*)_\b/print $1/ge'
HELO_WORLD

答案 2 :(得分:0)

有多个问题:

  • 你的sed命令是一个条件。它应该是一个动作,如s/pattern/replacement/flags或条件可以跟一个动作,即/_([^_+\n][\w]+)_/p来打印该行。

  • 使用sed,您需要转义括号和+或使用-r正则表达式扩展标记

  • [\w]\w本身已经是一个字符类,无需将其包含在类中

最后,用GNU grep拍摄我认为你想要的东西:

grep -P -o "_[^_+\n\s]\w+_"
$ echo "HELLO ___ _HELO_WORLD_" | grep -P -o "_[^_+\n\s]\w+_"
_HELO_WORLD_
  • 如果您只需要匹配,使用grep就足够了。
  • -o只能检索匹配的部分而不是整行
  • -P使用perl正则表达式,以便您可以将简写类用作\n\s
  • 我将\s添加到了否定的类中,因为之前它可以匹配您想要匹配的空格,因为\w可以匹配下划线。

如果你不能使用GNU grep,那么它又回到了sed,已经通过ceving回答了。

答案 3 :(得分:0)

正如许多答案和downvotes所暗示的那样,sed看起来不是用于此问题的正确工具,因此我最终使用了Python,其效果非常好,所以我将在此处发布对于将来可能遇到同样问题的人。

import re
p = re.compile('_([^_+\n][\w ]+)_')
result = p.findall(text)