【问题标题】:Match a pattern and insert text after it selectively in a large file匹配模式并在大文件中选择性地插入文本
【发布时间】:2019-08-13 03:10:48
【问题描述】:

我正在处理大量代码,需要重命名很多 API。这包括所有 API 的前缀。我的 API 名称类似于:

MyfoobarFilename_FooFighterDoMeAFavor(MyfoobarFilename_FooFighter *FighterInstance, void *Favor)
MyfoobarFilename_FooFighterGetInLine(MyfoobarFilename_FooFighter *FighterInstance, void *Line)
MyfoobarFilename_FooFighterSetATicketForMe(MyfoobarFilename_FooFighter *FighterInstance, void *Ticket)
MyfoobarFilename_FooFighterHelpMeNowInterrupt(MyfoobarFilename_FooFighter *FighterInstance, void *FighterReference)
MyfoobarFilename_FooFighterAreYouOk(MyfoobarFilename_FooFighter *FighterInstance, unsigned int HowAreYou)

我想通过在 API 名称中添加下划线来更改所有这些名称。
我希望结果如下所示,

MyfoobarFilename_FooFighter_DoMeAFavor(MyfoobarFilename_FooFighter *FighterInstance, void *Favor)
MyfoobarFilename_FooFighter_GetInLine(MyfoobarFilename_FooFighter *FighterInstance, void *Line)
MyfoobarFilename_FooFighter_SetATicketForMe(MyfoobarFilename_FooFighter *FighterInstance, void *Ticket)
MyfoobarFilename_FooFighter_HelpMeNowInterrupt(MyfoobarFilename_FooFighter *FighterInstance, void *FighterReference)
MyfoobarFilename_FooFighter_AreYouOk(MyfoobarFilename_FooFighter *FighterInstance, unsigned int HowAreYou)

但是,我只想替换 API 名称中的文本,而不是代码中的其他位置。我可以使用s/FooFighter/FooFighter_/g,但这也会做出我不想要的更改。

我可以通过多种方式通过使用脚本并执行 grep 和替换来做到这一点。
但是,必须有一种更快、更智能的方法来使用单个命令(希望使用 sed)来执行此操作。有人可以启发我如何做到这一点。

提前致谢。

【问题讨论】:

    标签: regex sed replace


    【解决方案1】:

    我推荐以下sed 表达式(使用Basic Regular Expression 语法):

    s/\(\bMyfoobarFilename_FooFighter\)\([a-zA-Z0-9_]\+\b\)/\1_\2/g
    

    在哪里

    • \b 转义序列代表“单词边界”(GNU 扩展);
    • \( ... \) 创建一个可以在s/regexp/replacement/ 命令的“替换”部分引用的组;
    • \1\2 是对第一组和第二组的引用;
    • g 指示 sed 将替换应用于“正则表达式”的所有匹配项,而不仅仅是第一个;
    • \+ 匹配一个或多个(GNU 扩展)。

    Perl 作为 GNU sed 的替代品

    正如@Wiktor Stribiżew 和@Ed Morton 所说,\+\b 是 GNU 扩展。您可以将\+ 替换为\{1,\}。但我找不到合适的符合 POSIX 标准的 \b 替代品。如果 GNU sed 不可用,您可以按如下方式使用 Perl:

    perl -i -npe \
    's/(\bMyfoobarFilename_FooFighter)(\p{L}+\b)/\1_\2/g' file
    

    其中\p{L}Unicode character property 代表一个字母。其余的和上面的 sed 表达式类似。


    您的 sn-ps 看起来像 C/C++ 函数原型,因此您可能也想修改函数调用和函数指针,例如:

    while (MyfoobarFilename_FooFighterHelpMeNowInterrupt ()
      && MyfoobarFilename_FooFighterSetATicketForMe())
      {
        /* ... */
      }
    
    void (*fptr)(MyfoobarFilename_FooFighter *, void *) =
      &MyfoobarFilename_FooFighterGetInLine;
    

    【讨论】:

    • 请注意\+是一个GNU sed扩展,但是OP没有在问题中指定sed版本,所以这里合适。
    【解决方案2】:

    试试这个:

    sed "s/\(MyfoobarFilename_FooFighter\)\(\S*(\)/\1_\2/g" file.txt
    

    解释:

    s/                                  # substitute
    \(MyfoobarFilename_FooFighter\)     # searchstring in \1
    \(\S*(\)                            # the rest to the bracket in \2
    /\1_\2                              # insert '_' between \1 and \2
    /g                                  # global
    

    【讨论】:

      猜你喜欢
      • 2018-11-13
      • 1970-01-01
      • 2013-07-02
      • 2016-07-09
      • 2023-01-22
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      • 2013-05-18
      相关资源
      最近更新 更多