【问题标题】:Perl REGEX substitute every ! with ~ only when surrounded by quotesPerl REGEX 替换每个 !与 ~ 仅当被引号包围时
【发布时间】:2020-10-01 19:21:44
【问题描述】:

我正在编写从 Fortran 77 到 Fortran 90 的转换脚本,并尝试使用 PERL REGEX 替换每个 !如果在引号内找到,则带有 ~。

这>'Hello !!!! Hello !!!!'变成>'Hello ~~~~ Hello ~~~~'

这>'Hello' !!!! 'Hello !!!!'变成>'Hello' !!!! 'Hello ~~~~'

我不知道如何使用音译,因为它只能在引号中使用 我能做的最好的事情是:

perl -pi -e "s/('.*?)\!+(.*')/\1~\2/g" File.txt

但这会将 4 个!s 替换为 1 个~,甚至不会更改第二组!s

这>'Hello !!!! Hello !!!!'变成>'Hello ~ Hello !!!!'

这>'Hello' !!!! 'Hello !!!!'变成>'Hello' !!!! 'Hello ~'

如果在\! 之后没有+,它只会替换第一个!,所以你会得到'Hello ~!!!'

我似乎无法计算每个! 并将其替换为~。而且我认为全球 /g 会同时获得两组 !s 但没有。

有什么想法吗?

【问题讨论】:

  • 有转义字符吗?例如:'Hello, I can\'t hear you'
  • 这不是正则表达式擅长的事情。他们不能数,所以没有办法说\!+应该被相同数量的~替换。
  • 输入中的正则表达式只有一个匹配项,因为它匹配引号之间的所有内容。所以它只执行一次替换,即使使用 g 修饰符。

标签: regex perl substitution


【解决方案1】:

匹配内部引号很困难。这更容易一些,因为只有一种类型的报价。假设我们必须满足 \' 转义,我们可以在后面使用否定查找来查找未转义的引号:(?<!\\)'/s 确保我们捕获而不考虑换行。 /g 捕获字符串中的每个匹配项。

下一个技巧是捕获引号之间的所有文本并仅对其进行处理。我们可以使用/e 替换一些对捕获的文本进行简单翻译的 Perl 代码:tr/!/~/

use strict;
use warnings;
use v5.10;

my $str = qq['Hello' !!!! 'Hello !!!! I can\\'t hear you!\n'];

$str =~ s{
    (?<!\\)' (.*?) (?<!\\)'
}{
    my $inner = $1;
    $inner =~ tr/!/~/;
    "'$inner'";
}egmsx;

# 'Hello' !!!! 'Hello ~~~~ I can\'t hear you~
# '
say $str;

【讨论】:

    【解决方案2】:

    我认为解析器而不是 REGEX 会是更好的答案。
    Schwern 您的回答似乎逐步完成了所有内容,但除非我读错了,否则它不会更新原始文件。

    感谢您的建议,但最后我使用了第三种方法。经过一些评估后,我确定我试图通过更改!来防止的情况不会像我想象的那样经常发生。因此,在通过我的转换器运行了所有 500K 行代码之后,我返回并手动修复了发生此问题的六个案例。 不过感谢您的逻辑练习。

    【讨论】:

      猜你喜欢
      • 2014-05-21
      • 1970-01-01
      • 1970-01-01
      • 2014-05-30
      • 2015-07-31
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      • 2015-11-20
      相关资源
      最近更新 更多