0

我有一个字符串

$test = 'xyz45sd2-32d34-sd23-456562.abc.com'

目标是获得 $1 = 23 和 $2 = 45 即最后一个两边的位数相等-。请注意,位数是可变的,不一定是 2。

我尝试了以下方法:

$test1 =~ s/.*(\d+)-(\d+).*//;

  • $1 包含 3
  • $2 包含 456562
4

5 回答 5

1

perl -e '"xyz45sd2-32d34-sd23-456562.abc.com" =~ /(\d{2})-(\d{2})\d*(?=\.)/; print "$1\n$2\n"'

于 2013-08-07T05:17:27.083 回答
1

此其他条目确认正则表达式不计算在内: 如何匹配字符数相同的单词

基于 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 是捕获长度的上限。

于 2013-08-07T05:44:04.687 回答
1

理论答案

简短的回答:

使用正则表达式无法找到您要查找的内容。

长答案:

正则表达式(顾名思义)是正则语言的紧凑表示(Type-3 grammars乔姆斯基层次结构中)。

您正在寻找的内容是不可能使用正则表达式的,因为您正在尝试写出一个维护某种计数的表达式(除beginningand之外的一些上下文信息end)。这种行为不能建模为DFA(实际上是任何有限自动机)。是否存在的非正式证明languageregular存在接受该语言的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, reverseand的所需数字部分来改进我的解决方案for

于 2013-08-07T11:32:39.033 回答
1

你可以试试这个正则表达式

if($test1 =~ m/(\S+)-(\S+)-([a-z]*)(\d+)-(\d\d)(\d+).*/)
{
    print $4,"|",$5;
}

我假设你只需要 456562 中的前 2 个数字

于 2013-08-07T05:06:15.847 回答
0

正如@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";
于 2013-08-07T18:59:51.250 回答