Sed regexp 仅匹配无效的 c++ 标识符字符以重命名变量

Sed regexp Match only non-valid c++ identifier characters to rename a variable

提问人:Ichwerdennauchsonst 提问时间:8/4/2023 最后编辑:Ichwerdennauchsonst 更新时间:8/29/2023 访问量:88

问:

我想使用 sed 重命名变量名称(标识符)。我想为 c++ 做这件事,但是对于其他语言来说,情况会类似。假设我们有一个这样的代码示例: 示例.cpp

int hi;
int bye;
...//a lot of code with many occurences of n

假设出于任何原因,我想在 hello 中重命名 hi。问题是 hi 可以作为其他词的一部分出现。在 C++ 中,有效的标识符具有以下收据:(将扩展字符放在一边,例如或放在一边。我不知道 alnum 是否包含这些,但如果它们没有问题,也许可以期待扩展的标点符号字符,但谁使用它们)[[[:alpha:]]_]+[[[:alnum:]]_]ä

有效标识符旁边必须有一个与此表达式无关的字符,以将其与其他标识符区分开来。因此,不允许在之前和之后使用,而任何其他字符都可以。另一个问题是字符串。这只有在字符串始终在内联时才有效。然后我们必须检查 unescpaped 的奇数出现“,如果我们可以使用正则表达式做到这一点,这可能是一个数学问题,但是我没有达到这一点,第一次在没有字符串识别的情况下尝试:n[[[:alnum:]]_]""

sed -i -e 'hi/\([^[[:alnum:]]_]\)hello\([^[[:alnum:]]_]\)/\1r\2/g' example.cpp

它没有改变任何东西

正则表达式 SED 标识符

评论

1赞 Barmar 8/4/2023
使用正则表达式执行此操作并不可行,并且无法正确确定所有上下文。大多数IDE都有一个“重命名变量”操作,它们知道如何解析语言并找到实际的变量用法。sed
1赞 Jarod42 8/4/2023
您的 IDE 可能具有重命名变量的函数(编译器具有不替换任何nr)
2赞 Some programmer dude 8/4/2023
与其从替换开始,不如搜索它,以确保正则表达式是正确的。当它出现时,你进行替换,但不是到位,让输出新文件以确保它做正确的事情。最后,您进行实际更换(但保留原件!sed
2赞 Pepijn Kramer 8/4/2023
理想情况下,您不会使用正则表达式,而是使用解析树并替换其中的出现。您可以查看使用 LLVM 和 AST(抽象语法树):例如,clang AST 简介
1赞 user4581301 8/4/2023
我可以说服您在执行替换时为变量提供描述性名称吗?现在可能不会让你的生活更轻松,但下一个必须处理这个代码的傻瓜,也可能是未来的你,会爱你。

答:

1赞 stevesliva 8/8/2023 #1

你的 sed 是乱码 -- 没有替代品。s///

无论如何,您所需要的只是在替换的匹配端中使用单词边界 ():\b

sed 's/\bhi\b/hello/' example.cpp

上面的作用与此几乎相同:

sed -E 's/([^[:alnum:]_])hi([^[:alnum:]_])/\1hello\2/' example.cpp

...除了上述取决于匹配组的大小为非零。

此处对单词边界的更多讨论。

另请注意,字符类的方括号多于所需数。的否定是,所以你的非单词字符类应该是 。这相当于在扩展正则表达式 (ERE) 中,因此您也可以使用:[[:alnum:]][^[:alnum:]][^[:alnum:]_]\Wsed -E

sed -E 's/(\W)hi(\W)/\1hello\2/' example.cpp 

...再次需要注意的是,在之前或之后必须有一个非单词字符(这可能是 C 变量的安全假设)。hi

要解决此问题,您也可以将行开头和结尾大小写添加到此行,这允许在这些情况下进行零大小匹配:^$

sed -E 's/(^|\W)hi(\W|$)/\1hello\2/' example.cpp 

(上面可能工作得很好,与sed 's/\bhi\b/hello/')

或者你可以使用 perl 正则表达式 (PCRE) 来使匹配组具有非消耗性 lookbehind 和 lookahead:(?<=)(?=)

perl -pe 's/(?<=\W)hi(?=\W)/hello/' example.cpp

与此相同,反转 char 组并否定 lookbehind 和 lookahead:

perl -pe 's/(?<!\w)hi(?!\w)/hello/' example.cpp

随着 GNU 正则表达式功能集的扩展,你可以用 grep 测试所有功能的匹配:

$ grep --color '\bhi\b' example.cpp
$ grep -E --color '(^|\W)hi(\W|$)' example.cpp
$ grep -P --color '(?<!\w)hi(?!\w)' example.cpp

...因此,您将看到使用基本、扩展 (ERE) 和 perl (PCRE) 正则表达式以颜色突出显示,所有这些都受 grep 支持。(上面的 ERE 还突出显示了之前或之后的非单词字符(如果有))hi

但是,所有正则表达式样式都支持始终方便的单词边界零大小匹配。所以,使用它。\b