在字符串中的字符两侧获得相同的数字位数

时间:2013-08-07 04:52:35

标签: regex perl sed

我有一个字符串

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

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

我尝试了以下内容:

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

但是

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

5 个答案:

答案 0 :(得分:1)

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

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

我认为你只需要456562的前2个答案

答案 1 :(得分:1)

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

答案 2 :(得分:1)

此其他条目确认正则表达式不计算: How to match word where count of characters same

基于GreatBigBore的想法,如果计数的上限,则可以尝试使用或运算符|。这只符合您查找匹配的要求;根据匹配的计数,匹配将在不同的箱中。只有一个案例正确地将它们放在$ 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是捕获长度的上限。

答案 3 :(得分:1)

理论答案

简答:

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

长答案:

正则表达式(顾名思义)是Regular languagesChomsky HeirarchyType-3 grammars)的简洁表示。

使用正则表达式无法找到您正在寻找的内容,因为您正试图写出一个维持某种计数的表达式(除了beginning和{{1之外的某些上下文信息) }})。这种行为无法建模为 DFA (实际上是任何有限自动机)。 end 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$rhs所需的数字部分而不是{{1},可以改进我的解决方案},splitreverse

答案 4 :(得分: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";