【问题标题】:How can I use sed/awk/perl to replace a matched pattern with an equivalent number of dashes?如何使用 sed/awk/perl 将匹配的模式替换为等量的破折号?
【发布时间】:2014-09-07 07:03:31
【问题描述】:

我想搜索文件中所有出现的模式,并将匹配项替换为等量的填充,例如空格或破折号。需要注意的是,我不想更改文件!我想将结果打印为标准输出。这就是为什么我更喜欢使用 sed。输出应该与文件的长度相同,因为我想用破折号中该模式的长度替换正则表达式找到的每个模式。 示例:假设文件包含以下内容:

data | more data | "to be dashed"

期望的输出:

data | more data | --------------

我目前有这样的事情:

sed -e 's/["][^"]*["]/-/g' file

导致:

data | more data | -

有什么想法吗?

【问题讨论】:

  • 感谢您的编辑,它现在看起来更具可读性。

标签: regex sed scripting escaping ksh


【解决方案1】:

使用 Perl:

perl -pe 's/(".*?")/ "-" x length($1) /ge' <<END
data | more data | "to be dashed"
data | "more data" | "multi words " "to be dashed"
END
data | more data | --------------
data | ----------- | -------------- --------------

由于您需要找到匹配文本的字符串长度,您需要通过一轮评估运行s///的替换部分,因此e标志。

【讨论】:

  • 绝对精彩!
【解决方案2】:

使用 GNU awk:

gawk 'BEGIN{ FS = "" }{ while (match($0, /^(.*)(["][^"]*["])(.*)$/, a)){ gsub(/./, "-", a[2]); $0 = a[1] a[2] a[3]; } } 1' file

例子:

$ echo 'data | more data | "to be dashed"' | gawk 'BEGIN{ FS = "" }{ while (match($0, /^(.*)(["][^"]*["])(.*)$/, a)){ gsub(/./, "-", a[2]); $0 = a[1] a[2] a[3]; } } 1'
data | more data | --------------

$ echo 'data | more data | "to be dashed" x "1234"' | gawk 'BEGIN{ FS = "" }{ while (match($0, /^(.*)(["][^"]*["])(.*)$/, a)){ gsub(/./, "-", a[2]); $0 = a[1] a[2] a[3]; } } 1'
data | more data | -------------- x ------

【讨论】:

  • 这很酷。不过,我不确定FS="" 的用途。是不是在重建$0 时不会发生逐行重组?
  • @ooga 这完全没有必要,但我只是不希望 FS 妨碍以防万一——不管它可能带来什么影响。
【解决方案3】:

sed 解决方案:

sed -r '
    :loop
      h                            # copy pattspace to holdspace
      s/(.*)("[^"]+")(.*)/\1\n\3/  # replace quoted field with newline
      T                            # if no replacement occurred, start next cycle
      x                            # exchange pattspace and holdspace
      s/.*("[^"]+").*/\1/          # isolate quoted field
      s/./-/g                      # change all chars to dashes
      G                            # append newline and holdspace to pattspace
      s/(-*)\n(.*)\n(.*)/\2\1\3/   # reorder fields using newlines
      t loop                       # repeat (must be conditional for T to work)
' file

OSX/BSD 可能没有 T 命令(如果自上次读取行或上次条件跳转后尚未进行替换,则跳转到标签(或下一个循环))。在这种情况下,将T 替换为:

t keeplooping      # branch over b if substitution occurred
b                  # unconditional branch to next cycle
:keeplooping

【讨论】:

  • 奇怪的是,这按原样打印了我的文件,并且没有进行任何替换..这在您的机器上有效吗?
  • ooga 使用星号,而不是引号。答案已编辑。
  • @glennjackman 谢谢。出于某种原因,我认为它是星号?!我再次对其进行了编辑以修复 cmets 以匹配。
猜你喜欢
  • 1970-01-01
  • 2019-10-14
  • 2017-06-16
  • 2013-06-01
  • 2018-08-12
  • 1970-01-01
  • 2020-04-27
  • 1970-01-01
  • 2021-12-24
相关资源
最近更新 更多