1

我正在尝试用“#”替换字符串中的所有数字,前提是它们没有特定的前缀。这些数字可以作为单词的一部分出现,也可以单独作为单词出现。

例如,使用 ABC 作为前缀,这是想要的结果。

输入:

sdkfjsd 12312981 sdkfjsdfhbnmawd 1298 ,smdfsdnfk2342423 
sdlkfsdfs 20349 ABC1203912 2034234aac <-- ABC<number> stays, the other numbers do not
ABC1203912

结果(请注意,第 2,3 行的 ABC 带有数字):

sdkfjsd # sdkfjsdfhbnmawd # ,smdfsdnfk#
sdlkfsdfs # ABC1203912 #aac <-- ABC<number> stays, the other numbers do not
ABC1203912

我试图用 regexp: 后面的负面外观来做到这一点s/(?<!ABC)\d+/#/g。在这种情况下,只有 ABC 之后的第一个数字不会被替换,其余的都会被替换。

我的下一步是将字符串拆分为包含 的部分,ABC\d+并对其他部分执行简单的替换。

将不胜感激任何建议如何在不拆分为多个字符串的情况下完成整个事情。

谢谢!

编辑 1:将 aac 移回正确位置。编辑 2:我正在使用 perl 5.8.5,以防万一。由于与我无法控制的代码的兼容性问题,我无法更新到较新的版本。

4

3 回答 3

3

我不明白您所说的“我的下一步是将字符串拆分为包含 的部分,ABC\d+并对其他部分执行简单的替换。”,但看起来这不是您的主要问题。否则请告诉我。

要匹配关键字前面没有的每个数字,ABC则可以使用此正则表达式:

(?<!ABC|\d)\d+

如果ABC在它之前有一个数字,或者另一个数字,这会阻止匹配(从而防止\d+从一个数字的中间开始匹配。

正则表达式101演示

请注意,您的问题中有两个部分的字符串移动了。我只接受你使用的输入。


如果上述方法不起作用(例如,正则表达式引擎说后视模式不能具有可变宽度,或者沿着这些线的东西),那么替代的等价物是:

(?<!ABC)(?<!\d)\d+

正则表达式101演示

于 2014-03-30T11:02:16.507 回答
1

并不完全清楚你想要什么,尤其是因为2034234aac在您的示例中对该字段进行了奇怪的修改。

但是,对您自己的负面回顾的这种修改可能会很有用。请注意,它会保留以 开头的任何ABC序列,例如ABCX1234. 目前尚不清楚这是否是正确的行为。

use strict;
use warnings;

my $s = <<'__END_TEXT__';
sdkfjsd 12312981 sdkfjsdfhbnmawd 1298 ,smdfsdnfk2342423 
sdlkfsdfs 20349 ABC1203912 2034234aac <-- ABC<number> stays, the other numbers do not
ABC1203912
__END_TEXT__

$s =~ s/\b(?!ABC)[a-z]*\K\d+/#/gi;

print $s;

或者,对于早于 10 的 Perl 5 版本,使用这个

$s =~ s/\b((?!ABC)[a-z]*)\d+/$1#/gi;

输出

sdkfjsd # sdkfjsdfhbnmawd # ,smdfsdnfk# 
sdlkfsdfs # ABC1203912 #aac <-- ABC<number> stays, the other numbers do not
ABC#
于 2014-03-30T11:05:29.453 回答
0

您需要使用“零宽度否定后向断言”:仅在没有紧接某些内容之前匹配。

例如。匹配前面没有的数字ABC

(?<!ABC)\d

您已经做到了这一点,但下一步要匹配前缀和多个数字:

(?<!ABC)\d+

没有直接帮助,因为您需要不匹配。

所以稍微改写一下这个问题:

替换不跟随前缀的数字和一个或多个数字

IE。在“ABC123”中,您不想替换 1、2 或 3。我们可以扩展零宽度负后向断言以包含数字:

(?<!ABC\d+)\d

因此也排除了前缀后面的数字。

注意,这假设 Perl 支持可变宽度的后视:当然,第一个包含后视的正则表达式扩展必须是固定宽度,但是自从我认真使用 Perl 正则表达式以来已经有一段时间了,所以我假设 Perl 正则表达式的实现已经扩展到匹配其他平台。

编辑:糟糕,s/positive/negative/lookbehind。

于 2014-03-30T10:40:55.567 回答