gpt4 book ai didi

regex - 使用sed替换仅用引号引起来的文本

转载 作者:行者123 更新时间:2023-12-04 04:07:19 25 4
gpt4 key购买 nike

我有这个测试文件。

[root @ localhost〜]#cat f.txt
“a aa” MM“bbb b”
MM MM
MM“b b”
[root @ localhost〜]#

我想替换引号中的所有空格字符,请注意,仅在引号中。引号中的所有字符都不应被触摸。也就是说,我想要的东西类似于:

“a_aa” MM“bbb__b”
MM MM
MM“b_b_”

可以使用 sed 来实现吗?

谢谢,

最佳答案

这是一个完全不平凡的问题。

这可以用下划线替换引号内的第一个空格:

$ sed 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' f.txt
"a_aa" MM "bbb_ b"
MM MM
MM"b_b "
$

对于此示例,在所有引号内最多包含两个空格的地方,很想简单地重复执行该命令,但是会给出错误的结果:
$ sed -e 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' \
> -e 's/\("[^ "]*\) \([^"]*"\)/\1_\2/g' f.txt
"a_aa"_ MM "bbb_ b"
MM MM
MM"b_b_"
$

如果您的 sed版本支持“扩展的正则表达式”,则适用于示例数据:
$ sed -E \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> -e 's/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/' \
> f.txt
"a_aa" MM "bbb__b"
MM MM
MM"b_b_"
$

您必须对双引号内的每个空格重复该令人讨厌的正则表达式-因此对于第一行数据要重复三遍。

正则表达式可以解释为:
  • 从一行的开头
  • 查找“零个或多个非引号,可选后跟一个引号,无空格或引号和一个引号”的序列,整个程序集重复零次或多次,
  • 后跟一个引号,零个或多个非引号,非空格,一个空格,零个或多个非引号以及一个引号。
  • 用开头部分,当前引用的段落开始处的 Material ,下划线和当前引用的段落的尾随 Material 替换匹配的 Material 。

  • 由于起始 anchor ,必须每个空白重复一次...但是 sed具有循环结构,因此我们可以使用以下方法:
    $ sed -E -e ':redo
    > s/^(([^"]*("[^ "]*")?)*)("[^ "]*) ([^"]*")/\1\4_\5/
    > t redo' f.txt
    "a_aa" MM "bbb__b"
    MM MM
    MM"b_b_"
    $
    :redo定义标签; s///命令与以前一样;如果自上次读取行以来进行了任何替换, t redo命令将跳转到标签,或跳转到标签。

    考虑到评论中的讨论,有两点值得一提:
  • -E选项适用于MacOS X上的sed(已测试10.7.2)。 GNU版本的sed的相应选项是-r(或--regex-extended)。 -E选项与grep -E(也使用扩展的正则表达式)一致。 “经典的Unix系统”不支持带有sed的ERE(Solaris 10,AIX 6,HP-UX 11)。
  • 您可以将我使用的?(这是唯一一个强制使用ERE而不是BRE的字符)替换为*,然后处理括号(在BRE中需要在它们前面加反斜杠以使它们变为捕获括号),然后保留以下脚本:
    sed -e ':redo
    s/^\(\([^"]*\("[^ "]*"\)*\)*\)\("[^ "]*\) \([^"]*"\)/\1\4_\5/g
    t redo' f.txt

    这会在相同的输入上产生相同的输出-我在输入中尝试了一些稍微复杂的模式:
    "a aa"  MM  "bbb  b"
    MM MM
    MM"b b "
    "c c""d d""e e" X " f "" g "
    "C C" "D D" "E E" x " F " " G "

    这给出了输出:
    "a_aa"  MM  "bbb__b"
    MM MM
    MM"b_b_"
    "c_c""d_d""e__e" X "_f_""_g_"
    "C_C" "D_D" "E__E" x "_F_" "_G_"
  • 即使使用BRE表示法,sed也支持\{0,1\}表示法来指定0个或1个先前RE项的出现,因此可以使用以下命令将?版本转换为BRE:
    sed -e ':redo
    s/^\(\([^"]*\("[^ "]*"\)\{0,1\}\)*\)\("[^ "]*\) \([^"]*"\)/\1\4_\5/g
    t redo' f.txt

    这将产生与其他替代方案相同的输出。
  • 关于regex - 使用sed替换仅用引号引起来的文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8265854/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com