【问题标题】:How can I repeat a Perl Regular Expression until no changes are left?如何重复 Perl 正则表达式直到没有任何更改?
【发布时间】:2026-01-20 20:25:02
【问题描述】:

我正在尝试编写一个简单的命令行脚本来修复一些空格,并且需要用制表符替换出现的两个空格,但前提是它出现在行首(仅由其他制表符前缀。)

我想出了s/^(\t*)  /\1\t/g;,如果我通过多次传递,它可以完美地工作,但是我对 perl 的了解不够,不知道如何循环,直到字符串没有改变,或者是否有正则表达式方式处理它。

我唯一的想法是使用lookbehind,但它不能是可变长度。如果它足够短以适合快速命令行脚本,我会接受非正则表达式解决方案。

作为参考,当前的 perl 脚本是这样执行的:

perl -pe 's/^(\t*)  /$1\t/g'

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    检查a very similar question

    您可以使用1 while s/^(\t*) /$1\t/g; 重复该模式,直到无需进行任何更改。

    【讨论】:

    • 感谢您的链接 - 我继续并在您的帖子中添加了解决方案。
    • \1(一种表示“匹配$1 中的内容”的模式)在替换表达式中是错误的。应该是$1
    • 哦,我刚刚指出了一个类似的问题。你是对的。
    • @ikegami 这就是附加信息 - 我编辑了他的帖子以反映这些注释......
    • 嗨,系统故障。你能进一步解释一下吗? 1 while 对我来说似乎很奇怪?为什么它会起作用?
    【解决方案2】:

    perl -pe 's{^(\t*)((  )+)}{$1 . "\t" x (length($2)/length($3))}e'
    

    【讨论】:

      【解决方案3】:

      支持空格和制表符的混合:

      perl -pe'($i,$s)=/^([ \t]*)([.*])/s; $i=~s/  /\t/g; $_="$i$s";'
      

      【讨论】:

        【解决方案4】:

        这是 Perl,因此您不必执行循环。相反,您可以只在替换表达式中进行评估,如下所示:

        my $tl = 4;
        s{ ( \t* ) ( [ ]* ) }
         { my $l=length( $2 ); 
           "$1" . ( "\t" x int( $l / $tl )) . ( ' ' x ( $l % $tl ))
         }ex
        ;
        

        【讨论】:

        • @Bill Ruppert 这基本上是单行的。 $tl 只是显示每个制表符的空格数是如何工作的。