我有一个字符串
$test = 'xyz45sd2-32d34-sd23-456562.abc.com'
目标是获得 $1 = 23 和 $2 = 45 即最后一个两边的位数相等-
。请注意,位数是可变的,不一定是 2。
我尝试了以下方法:
$test1 =~ s/.*(\d+)-(\d+).*//;
但
- $1 包含 3
- $2 包含 456562
perl -e '"xyz45sd2-32d34-sd23-456562.abc.com" =~ /(\d{2})-(\d{2})\d*(?=\.)/; print "$1\n$2\n"'
此其他条目确认正则表达式不计算在内: 如何匹配字符数相同的单词
基于 GreatBigBore 的想法,如果计数有上限,那么您可以尝试使用 or 运算符 |。这仅符合您找到匹配项的要求;根据匹配的计数,匹配将在不同的箱中。只有一个案例正确地将它们放在 1 美元和 2 美元中。
(\d{3})-(\d{3})|(\d{2})-(\d{2})|(\d{1})-(\d{1})
但是,如果您将结果捕获连接为 $1$3$5 和 $2$4$6,您将有效地获得您正在寻找的 2 个刺痛。
另一个想法是迭代操作,您可以通过增加数字来重复搜索字符串,直到匹配失败。 (\d{1})-(\d{1})
, (\d{2})-(\d{2})
...
想到二进制搜索,使其成为 O{ln(N)},N 是捕获长度的上限。
使用正则表达式无法找到您要查找的内容。
正则表达式(顾名思义)是正则语言的紧凑表示(Type-3 grammars
在乔姆斯基层次结构中)。
您正在寻找的内容是不可能使用正则表达式的,因为您正在尝试写出一个维护某种计数的表达式(除beginning
and之外的一些上下文信息end
)。这种行为不能建模为DFA(实际上是任何有限自动机)。是否存在的非正式证明language
是regular
存在接受该语言的DFA 。由于这种上下文信息不能在DFA中建模,因此矛盾的是,您不能为您的问题编写正则表达式。
my ($lhs,$rhs) = $test =~ /^[^-]+-[^-]+-([^-]+)-([^-.]+)\S+/;
# Alernatively and faster
my (undef,undef,$lhs,$rhs) = split /-/, $test;
# Rest is common, no matter how $lhs and $rhs is extracted.
my @left = reverse split //, $lhs;
my @right = split //, $rhs;
my $i;
for($i=0; exists($left[$i]) and exists($right[$i]) and $left[$i] =~ /\d/ and $right[$i] =~ /\d/ ; ++$i){}
--$i;
$lhs= join "", reverse @left[0..$i];
$rhs= join "", @right[0..$i];
print $lhs, "\t", $rhs, "\n";
编辑:$lhs
可以通过使用正则表达式提取and$rhs
而不是split
, reverse
and的所需数字部分来改进我的解决方案for
。
你可以试试这个正则表达式
if($test1 =~ m/(\S+)-(\S+)-([a-z]*)(\d+)-(\d\d)(\d+).*/)
{
print $4,"|",$5;
}
我假设你只需要 456562 中的前 2 个数字
正如@Samveen 所说,在纯正则表达式中从技术上讲是不可能的
就像@Samveen 解决方案一样,这是另一个版本
#get left and right
my (undef,undef,$left,$right) = split /-/, $test;
#get left numbers
$left =~ s/.*?(\d+)$/$1/;
##get right numbers
$right =~ s/^(\d+).*/$1/;
##get length of both
my $right_length = length $right;
my $left_length = length $left;
if ($right_length > $left_length){
#make right length as same as left length
$right =~ s/(\d{$left_length}).*/$1/;
} else {
#make left length as same as right length
$left =~ s/.*(\d{$right_length})/$1/;
}
print $left, "\t", $right, "\n";