Perl正则表达式-将字符串中的所有数字替换为#,除非它们有特定的前缀



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

例如,使用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之后的第一个数字将不会被替换,其余数字将被替换。

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

如果有任何关于如何在不分成多个字符串的情况下完成整件事的建议,我将不胜感激。

谢谢!

编辑1:将aac移回正确位置。编辑2:我使用的是perl5.8.5,以防与此相关。由于与我无法控制的代码的兼容性问题,我无法更新到新版本。

我不明白你说的"我的下一步是将字符串拆分为包含ABCd+的部分,并对其他部分执行简单的替换"是什么意思,但这似乎不是你的主要问题。否则请告诉我。

要匹配每个前面没有关键字ABC的数字,可以使用以下regex:

(?<!ABC|d)d+

如果一个数字之前有ABC,这将阻止该数字的匹配,或者另一个数字(因此,如果从数字中间开始,则阻止d+匹配。

regex101演示

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


如果上面的方法不起作用(例如,正则表达式引擎说lookbacking中的模式不能是可变宽度的,或者是类似的(,那么另一个等价物是:

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

regex101演示

还不完全清楚您想要什么,尤其是因为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]*Kd+/#/gi;
print $s;

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

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

输出

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

您需要使用一个"零宽度负向后看断言":只有在没有紧跟在前面的情况下才匹配。

例如。匹配不在ABC:前面的数字

(?<!ABC)d

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

(?<!ABC)d+

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

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

替换不在前缀后面的数字和一个或多个数字

Ie。在"ABC123"中,您不想替换1、2或3。我们可以将零宽度负后备断言扩展到包括数字:

(?<!ABCd+)d

从而也排除了前缀后面的数字。

NB这假设Perl支持可变宽度的lookbehinds:当然,正则表达式的第一个扩展包括lookbehind,它们必须是固定宽度的,但我已经有一段时间没有认真使用Perl正则表达式了,所以我假设Perl正则表达式的实现已经扩展到匹配其他平台。

编辑:糟糕,s/正面/负面/落后。

最新更新