【问题标题】:sed multiline search-replacesed 多行搜索替换
【发布时间】:2021-02-18 03:27:58
【问题描述】:

我得到了令人讨厌的旧语法的 fortran 代码,并希望移植到新语法。 我的 sed 命令

sed -nr 'N;s/\n\s*\d\D\s*//g' file 

应该找到编号的换行符,但由于我不知道的原因不起作用。我已经在这里查看了许多 multiline-sed 问题,但我仍然无法解决我的误解。据我了解,该命令的工作方式如下:

N                   append next line to pattern space; thus pattern space has two lines with \n in between
s///g               usual search-replace
\n\s*\d\D\s*        matches a newline followed by \s*, a digit, a non-digit and a \s* again

源代码看起来像

   if(condition) then 
         call func1(v1, v2, v3, v4
     1              ,v5,v6,v7)
      else
         call func2(v1, v2, v3, v4
     1              ,v5,v6,v7)
      endif
call MPI_BCAST(num(1),1,MPI_DOUBLE_PRECISION
     1     ,masterid,comm,mpinfo)
21      format(' text',2x,f10.5)

并且应该转换为目标代码

   if(condition) then 
         call func1(v1, v2, v3, v4,v5,v6,v7)
      else
         call func2(v1, v2, v3, v4,v5,v6,v7)
      endif
call MPI_BCAST(num(1),1,MPI_DOUBLE_PRECISION,masterid,comm,mpinfo)
21      format(' text',2x,f10.5)

【问题讨论】:

  • sed 不支持\d\D.. \sGNU sed 支持(不确定其他实现)...另外,使用N(无需额外解决方法命令)将阻止您再次使用该行。例如,前两行是配对的,因此您将永远无法匹配您需要的第三行

标签: regex sed replace multiline


【解决方案1】:

下面是perl 的一种可能的解决方案,适用于给定的样本输入:

perl -0777 -pe 's/\n\h*\d\h*(?=,)//g'
  • -0777 slurp 整个输入作为单个字符串
  • \n\h*\d\h* 匹配换行符,后跟可选的水平空格,后跟一个数字字符,后跟可选的水平空格
    • (?=,) 仅在此类匹配后有逗号字符时才匹配...否则,您需要告诉如何不匹配 21 format(' text',2x,f10.5)

使用GNU sed,但我对这些命令的理解还不够自信:

sed -E 'N; s/\n\s*[0-9]\s*,/,/; P; D'

来自GNU sed manual

P打印出模式空间的部分,直到第一个换行符。

D 如果模式空间不包含换行符,则开始一个正常的新循环,就像发出了 d 命令一样。否则,删除模式空间中的文本直到第一个换行符,然后使用生成的模式空间重新开始循环,而不读取新的输入行。

【讨论】:

  • 您的perl 解决方案就像一个魅力!您的sed 示例也帮助我更好地理解了它背后的机制。但在深入了解perl 之前,我尝试坚持使用sed,尽管我相信perl 在许多情况下要简单得多。
【解决方案2】:

这可能对你有用(GNU sed):

sed -E ':a;N;s/\n\s*[0-9]\s*([^0-9])/\1/;ta;P;D' file

使用 2 行窗口遍历文件。

如果第二行以一些或没有空格开始,然后是一个数字,然后是一些更多或没有空格,然后是一个非数字,用非数字替换它并重复。否则打印窗口的第一行,然后删除它并重复。

【讨论】:

  • 非常感谢,这对我有用!但我对@Sundeep 的评论有点困惑。如果 sed 使用命令 N 在联合行 12、34、56...而不是 12、23、34...中读取文件,那么我看不到上述命令如何匹配 23 中的换行符, 45, ...但显然它确实如此?!
  • D 命令的特殊之处在于它不仅删除模式空间中的第一个换行符(包括第一个换行符),而且如果模式空间不是空的,它会抑制下一个的隐式读取行,而是跳转到 sed 循环中的第一个命令。因此,如果模式空间中有 2 行,则第二行变为第一行。
  • 非常感谢您的详细解释。我想我明白了!
猜你喜欢
  • 2011-08-15
  • 2018-11-16
  • 2018-12-22
  • 2014-09-13
  • 2011-08-16
  • 2011-08-16
  • 2010-11-05
  • 2020-11-22
相关资源
最近更新 更多