将忽略任何注释匹配的 sed 命令

Vra*_*all 6 sed text-processing regular-expression

我正在尝试使用正则表达式创建 sed 命令,以便仅在没有注释的情况下替换文本文件中的某些内容,但由于我几乎不了解 sed 命令的知识,我遇到了一些麻烦。

我为问题的一小部分找到了解决方案,但有些还不够完整,或者我无法将它们放在一起。TL; DR 版本在最后可用。

让我们先确定我的最终目标

只有在没有注释的情况下,我才想在文本文件中匹配任何内容(如任何常规正则表达式(呵呵))。因为我想为多种语言做这件事,让我们只看常见的 C 注释。

因此,在这种情况下,可以以不同方式对单词或行进行注释。我们//只有评论线路上的下一个内容,我们还有/* */评论块。


环境

我目前正在使用仅支持 POSIX sed 的 Mac OSX,但我安装了一个我发现更好的 GNU-sed。(感谢Homebrew. 包是gnu-sed,命令是gsed。)所以,如果您喜欢使用其中一种或另一种,我可以使用它们。

我在写这篇文章时假设使用了 GNU-sed。


忽略一个案例

第一个问题,如何忽略某些情况。我在这个话题中很容易地发现了这一点

现在,这//部分对我来说似乎很容易做,我只需要添加一个OR ( |)条件即可将其与另一个条件连接起来。

它看起来像这样:

    sed -E "/\/\/.*/! s/foo/bar/" file
Run Code Online (Sandbox Code Playgroud)

然后,如果输入文件是:

foo
42
test
//foo
//42
//    foo
//something foo
foo
42
something foo
  foo
Run Code Online (Sandbox Code Playgroud)

输出是:

bar
42
test
//foo
//42
//    foo
//something foo
bar
42
something bar
  bar
Run Code Online (Sandbox Code Playgroud)

所以现在,我只想把我的反思集中在/* */评论块上。


通过多行匹配

第二个问题,如何通过多行使正则表达式匹配。嗯,我认为这是主要问题。我找到了这个话题在讨论如何仅通过一个新行字符进行匹配。好吧,我花了一点时间才明白它是如何工作的。但是这部分解决方案给我带来了一个新问题和新问题。

它显然只能忽略一个新行 ( \n)。所以我现在想要做同样的事情,但是对于未知数量的行(从 0 到无限 ( *))。我敢打赌我必须遍历这些行,但这就是我被卡住的地方,因为我对 sed 的命令一无所知,这对我来说真的很尴尬。

在我的搜索过程中,我发现了一个用于替换命令的小脚本tail它使用了一个循环(我猜),但我无法理解它的功能。

使它只在*/零件之前匹配

第三部分是确保忽略的大小写仅匹配注释块 ( */)结尾之前的内容。因此,最后,ignore case 只会匹配/*和之间的内容*/。最后的命令将完全忽略注释块中写入的内容。

我没有对这部分进行真正的搜索,因为我没有解决上一点,在我看来,这个*/问题取决于上/*一个问题。


最后一部分:将所有这些放在一起

嗯,很明显我现在完全失败了。


TL; 博士

我的问题是: sed 命令是什么,以便仅在没有注释的情况下替换文本文件中我们想要的任何内容?


附录

如果您知道使用任何其他语言的更简单的方法,也非常欢迎。所以,如果你知道如何与做awkpython或者别的什么,随时分享。

mik*_*erv 10

如果他们告诉你这是不可能的,你不应该相信他们。然而,如果他们告诉你这并不容易,你应该相信他们

sed '\|*/|!{ s|/\*|\n&|              #if ! */ repl 1st /* w/ \n/*
     h;      s|foo|bar|g;/\n/!b      #hold; repl all foo/bar; if ! \n branch
     G;      s|\n.*\n||;:n           #Get; clear difference; :new label
     n;      \|*/|!bn;s|^|\n/*|      #new line; if ! */ branch new label
     };s|*/|\n&|g                    #repl all */ w/ \n*/
       s|foo|&\nbar|g;:r             #repl all foo w/ foo\nbar
       s|\(/\*[^\n]*\)\nbar|\1|g;tr  #repl all /*[^\n]*\nbar w/ foo
       s|foo\n\(b\)|\1|g             #repl all foo\nbar w/ bar
       s|^\n/.||;s|\n||g             #clear any \n inserts
'    <<\INPUT
asfoo   /* asdfooasdfoo


asdfasdfoo
asdfasdfoo
foo */foo /*foo*/ foo
/*.
foo*/
foo
hello

INPUT
Run Code Online (Sandbox Code Playgroud)

输出

asbar   /* asdfooasdfoo


asdfasdfoo
asdfasdfoo
foo */bar /*foo*/ bar
/*.
foo*/
bar
hello
Run Code Online (Sandbox Code Playgroud)