【问题标题】:Replace characters following, and within distance to, keyword替换关键字之后和距离内的字符
【发布时间】:2015-09-29 14:57:31
【问题描述】:

使用 sed,我如何替换关键字后面的字符,但 在所述关键字末尾的 x 个字符内。例如,假设字符串:

foo bar baz quz

假设关键字是bar,字符z将被替换为字符t,但只能在关键字结尾的3个字符内(不包括空格)。

期望的结果是:

foo bar bat quz

编辑:我猜这里可能会指出扩展正则表达式的用法,但不确定如何使用。

sed -re 's/(::bar) some_regex_magic_here /' infile

【问题讨论】:

  • @dustmouse 您的建议与用户 Joe 的回复中所述的问题相同:echo "foo bar bzz quz" | sed -re 's/(bar.{3})z/\1t/' 给出了foo bar bzt quz,而不是所需的foo bar btt quz

标签: regex sed


【解决方案1】:

使用 awk 你可以做到:

s="foo bar baz quz"

awk -v kw='bar' -v pos=3 'p=index($0, kw){n=p+length(kw)+1; s=substr($0, n, pos);
     gsub(/z/, "t", s); $0=substr($0, 1, n-1) s substr($0, n+pos)} 1' <<< "$s"

输出:

foo bar bat quz

更多测试:

s='foo bar bzz quz'
awk -v kw='bar' -v pos=3 'p=index($0, kw){n=p+length(kw)+1; s=substr($0, n, pos);
     gsub(/z/, "t", s); $0=substr($0, 1, n-1) s substr($0, n+pos)} 1' <<< "$s"
foo bar btt quz

【讨论】:

  • 谢谢。但是,当应用于多行时,您的 awk 代码会省略没有关键字的行。例如:echo -e "foo bar bzz quz\nfoo bzz quz\nfoo bar bzz quz" &gt; tmp &amp;&amp; awk -v kw='bar' -v pos=3 'p=index($0, kw){n=p+length(kw)+1; s=substr($0, n, pos); gsub(/z/, "t", s); print substr($0, 1, n-1) s substr($0, n+pos)}' tmp你能调整你的代码以保持这样的行吗?
  • 用户 anubhava 的回答效果很好!感谢他的努力。
【解决方案2】:

您可以使用以下命令完成此操作:

sed -E 's/(bar[[:space:]]*(.[[:space:]]*){0,2})z/\1t/'`

例子:

echo "foo bar baz quz" | sed -E 's/(bar[[:space:]]*(.[[:space:]]*){0,2})z/\1t/'

它的工作原理是捕获bar,后跟任意数量的空白,但最多只能有 2 个非空白字符,然后是 z,并将其替换为捕获组 1,后跟 t-E 是 OSX 的扩展正则表达式标志,如有必要,请将其更改为您平台的扩展正则表达式标志。

【讨论】:

  • 谢谢。虽然您的代码确实适用于上述示例,但当相关字符出现不止一次时,它会失败。例如:echo "foo bar bzz quz" | sed -re 's/(bar (\s*[^\s]){0,3})z/\1t/'
  • sed 不再是您的工具,请参阅 awk 答案。
猜你喜欢
  • 2015-01-05
  • 1970-01-01
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多