我正在尝试删除由空格分隔的字符串中的所有数字/标点符号组合,即
$string = " 13-acetate 9-11 777 >3 ctl-54 2!3 ";
应该成为
$string = " 13-acetate ctl-54 ";
我的尝试如下
$string =~ s/\s+[\d*[:punct:]>]+\s+//g;
但是这给了我
$string = " 13-acetate 777 ctl-54 ";
欣赏指示我出错的地方。
答案 0 :(得分:5)
问题在于你试图在两次传球中匹配相同的空间。你需要使用外观。
s/(?<!\S)[\d\p{Punct}\p{Symbol}]+(?!\S)//g;
我使用了负向前看并查看背后,因此您不需要在输入字符串中添加前导和尾随空格。
答案 1 :(得分:0)
正如池上所指出的,你的问题是你试图将这两个空间匹配。
快速修复原始正则表达式的另一种方法是为开始边界条件创建一个替换:
use strict;
use warnings;
my $string = " 13-acetate 9-11 777 >3 ctl-54 2!3 ";
$string =~ s/(?:\G|\s+)[\d[:punct:]]+\s+/ /g;
print $string;
输出:
13-acetate ctl-54
然而,这种方法存在缺陷,因为它不允许剥离字符串开头或结尾的单词。这就是为什么在强制执行边界条件时,负向前瞻和后视是优越的。
如果你想要用一种聪明的方式来表达和消除单词周围的间距,那么下面的方法就可以了:
$string =~ s{(?:\G|(\s+))[\d[:punct:]]+(?:$|(\s+))}{
my @spaces = grep defined, $1, $2;
pop @spaces;
"@spaces"
}eg;
输出:
13-acetate ctl-54