Perl - 用变量的内容替换数字字符串

时间:2013-11-24 10:38:44

标签: perl numbers escaping pattern-matching

我正在尝试使用变量替换一行中的一些数字,我遇到了无法解决的问题。以下输入:

    111111  133433.000  222222  5225.9860   360 01333.4400  90  10.37   137.71  190410
    111111  133434.000  222222  5225.9837   360 01333.4432  90  1.11    138.34  190410

脚本应使用第一行中的1.11替换第二行中的值10.37。要处理的文件中有几千行,因此将对行进行评估,并将数字1.1110.37存储在变量中。在这种特殊情况下:

$speed = 1.11 
$speed_p = 10.37
$tmpline - current processed line (part of an array)

我用这个替换:

$tmpline =~ s/$speed/$speed_p/eeg;

不幸的是,这个命令忽略了$speed中的“点”,我得到了第二行的以下结果:

    10.3711 133434.000  222222  5225.9837   360 01333.4432  90  10.37   138.34  190410

所以命令用新值替换1111.11,有没有办法改进这个并逃避变量中的“点”?

提前致谢!

亚历

1 个答案:

答案 0 :(得分:2)

句点.是一个正则表达式元字符,它是一个通配符,它​​匹配除换行符\n之外的任何内容。您需要做的是禁用句点的元状态,这通常使用反斜杠。但是,在您的情况下,您可以使用\Q ... \E转义序列:

$tmpline =~ s/\Q$speed\E/$speed_p/g;

另请注意,我删除了双重评估/ee修饰符。它们不是必需的,使用起来很危险。

但它并不止于此,因为您仍然可以部分匹配1.11(例如它可以匹配21.1123)。因此,您需要确保匹配整个数字:

$tmpline =~ s/(?<!\S)\Q$speed\E(?!\S)/$speed_p/g;

我在这里使用双重否定,带有lookbehind和lookahead断言,以确保数字两边的字符不是非空格。双重否定意味着处理边缘情况,因为它认为字符串的开头或结尾是可接受的。如果您确定数字周围始终有空格,则只需使用(?<=\s)(?=\s)即可。