【问题标题】:Need Assistance with understanding this regex in sed需要帮助来理解 sed 中的这个正则表达式
【发布时间】:2013-01-09 01:25:17
【问题描述】:

我发布了this question,有人回答了这个

sed '/^void.*{$/!b;:a;/\n}$/bb;$!{N;ba};:b;s/\n/&test1&/;s/\(.*\n\)\(.*\n\)/\1test2\n\2/' file

我是 sed 和正则表达式的新手,无法理解每个部分的功能。

我将尝试解释我所理解的内容,你们可以填补缺失的东西。我会一个字一个字地去

  1. ^void.*{$ -- 这意味着任何以void 开头并以{ 结尾的东西
  2. /!b; 我不明白这是做什么的。现在bbranching/ 在那里做什么
  3. :a; 用于制作标签a
  4. /\n 又没看懂 / 那里
  5. }$} 结尾
  6. /bb我不明白
  7. $! 表示如果不是文件结尾
  8. {N; 没有明白它的意思,N 表示复制缓冲区中的下一行但确实得到了 {
  9. :b 没听懂。 b 用于分支,但不知道它在那里做什么 10.s/\n/&test1&/ 我认为它用\ntest1\n 替换 \n 但不确定
  10. s/\(.*\n\)\(.*\n\)/\1test2\n\2/这个也别买了

【问题讨论】:

  • 看起来回答你问题的人添加了an explanation
  • 他在组中添加了解释,我什至不明白。我想逐个字符地理解
  • sed 是在单行上进行简单替换的出色工具,但对于其他任何事情,您应该使用 awk 代替。我已经使用 sed 30 年了,甚至无法猜测您发布的命令在做什么。如果您发现自己使用的不仅仅是“s”和“g” sed 命令,那么您可能使用了错误的工具,所以不要在这些东西上浪费您的时间,只需获得一个 awk 解决方案,它会更清晰、更简单和将来更容易增强。
  • @Ed Morton,我以前使用过 awk,但人们一直说使用 sed。真的,我无法区分何时使用什么。我现在将发布新问题(如果那没有关闭”),以便了解何时使用什么
  • @user1953864 - 使用 sed 解决中等复杂问题的吸引力与解决难题的吸引力相同。如果你能弄清楚标点符号和字母的正确神秘组合,那么你会自我感觉良好,并且进行了良好的心理锻炼,但最终你什么也没做。有关 sed 何时是正确使用工具的具体建议,请参阅我之前的评论。

标签: regex linux sed


【解决方案1】:

您可以将多个 sed 表达式与 ; 字符链接在一起。下面分别看一下。

第一个表达式/^void.*{$/!b 在分隔符/ 之间有一个匹配器表达式。它匹配:

^ - 行首

void - 后跟字符“void”

.* - 后面是任何东西

{ - 后跟左卷曲

$ - 后跟行尾

第一个表达式中的修饰符 !b 表示如果匹配器不匹配,则中止 sed 评估。

:a 表达式是一个标签。它与称为分支的类似 goto 的 sed 功能一起使用。我们将在下一个表达式中看到标签是如何使用的。

表达式/\n}$/bb 匹配:

\n - 换行

} - 后跟右卷曲

$ - 后跟行尾

修饰符bb 表示如果找到匹配项,则“分支”到标签b。标签 b 在后面的表达式中定义为:b

$!{N;ba} 表达式应该被读为一个,即使它的中间有一个 ;。在这种情况下,花括号代表一系列要一起执行的命令。

$! - 如果不是输入结束

{ - 启动命令组(在这种情况下,有两个)

N - 静默读另一行

ba - 标记 a 的分支

} - 结束命令组

接下来是标签:b,当我们通过/\n}$/bb 表达式单独匹配一行上的单个} 时,我们将点击该标签。

最后有两种替代模式,它们是非常标准的正则表达式。表达式之前的s 本质上表示s/find_this/replace_it_with_this/。对于s/\n/&test1&/,我们有:

\n - 查找换行符

/ - 并将其替换为

& - 第一个表达式中匹配的内容(在本例中为换行符)

test1 - 单词 test1

& - 又是匹配的东西

所以基本上s/\n/&test1&/ 意味着用\ntest1\n 替换下一个\n

最后一个表达式类似,但引入了一个叫做捕获的东西。捕获让您仍然可以匹配所有内容,但保留 \(\) 之间的所有内容以用于表达式的替换部分。例如,如果给定输入字符串abcdes/a\(b\)c\(d\)e/\1 \2/ 将输出b d。在示例中,\1\2 分别替换为转义括号中捕获的内容,bd

s - 这是一个替换模式:

/ - 查找

\( - 并放入\1 替换变量

. - 任何东西

* - 以及任意数量

\n - 包括您遇到的第一个换行符

\) - (\1 的捕获结束)

\( - 并放入\2 替换变量

. - 任何东西

* - 以及任意数量

\n - 包括您遇到的第一个换行符

\) - (\2 的捕获结束)

/ - 全部替换为

\1 - 捕获的第一件事,

test2\n - test2\n,

\2 - 捕获的第二个东西。

【讨论】:

    【解决方案2】:

    这个词:

    /^void.*{$/!b
    

    表示匹配^void.*{$,斜杠是正则表达式周围的正则表达式分隔符。所以你得到/^void.*{$/。如果感叹号跟在/regex/! 中的匹配表达式后面,那么这意味着如果正则表达式匹配not,则执行以下命令。以下命令是b,它是分支。其中,没有标签名称,在脚本末尾分支。所以总的来说,这个表达式试图匹配^void.*{$(即,以void开头并以{结尾的行)并跳过(b)脚本的其余部分以防匹配失败(!)。

    这个东西:

    :a;/\n}$/bb;$!{N;ba};
    

    开始一个标签:a; 并尝试匹配\n}$(一个换行符和一行上的一个}),它再次包含在/regex/ 中。在匹配时,它会分支(b)到标签 b(因此,/regex/bb)。如果这不是输入的结尾 ($!),则读取一行 N 并跳回标签 a (ba)。这里的卷曲对(即{commands})创建了一个块。这块 如果$! 为真,则作为一个整体执行,这意味着有更多的输入。所以$!{N;ba} 只是意味着:

    If not end of input:
    begin
       real line
       jump to label a
    end
    

    【讨论】:

    • 谢谢哥们,我现在明白了
    猜你喜欢
    • 1970-01-01
    • 2011-10-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-30
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多