Perl拆分功能 - 使用重复字符作为分隔符

时间:2015-09-21 03:19:32

标签: regex perl

我想使用重复字母作为分隔符来拆分字符串,例如, SET ServerPath=\\IYA-PC\Shared SET ClientPath=%USERPROFILE%\Documents\Data Log echo. echo Copying Files to Server... SET FILE_NAME=ERR%date:~2,2%%date:~5,2%%date:~8,2%.txt FOR /F "delims=|" %%I IN ('DIR "%ClientPath%\%FILE_NAME%" /B /O:F') DO SET NewestFile=%%I xcopy "%ClientPath%" "%ServerPath%\%NewestFile%" /s /c /d /e /h /i /r /y 应分为"123aaaa23a3",而('123', '23a3')应保持不变 所以我尝试了这个:

"123abc4"

但这会返回@s = split /([[:alpha:]])\1+/, '123aaaa23a3'; ,这不是我想要的。现在我知道这是因为'123', 'a', '23a3'中的'a''aaaa'捕获并由split()保留。但无论如何,我无法添加?:之类的内容,因为必须捕获[[:alpha:]]以供后面参考。 我该如何解决这种情况?

3 个答案:

答案 0 :(得分:4)

嗯,这是一个有趣的。我的第一个想法是 - 你的分隔符将永远是奇数,所以你可以丢弃任何奇数编号的数组元素。

也许是这样的事情?:

my %s = (split (/([[:alpha:]])\1+/, '123aaaa23a3'), '' );
print Dumper \%s;

这会给你:

$VAR1 = {
          '23a3' => '',
          '123' => 'a'
        };

因此,您可以通过keys提取您的模式。

不幸的是,我通过%+“选择”模式匹配的第二种方法没有特别的帮助(拆分不会填充正则表达式的东西)。

但是这样的事情:

my @delims ='123aaaa23a3' =~ m/(?<delim>[[:alpha:]])\g{delim}+/g; 
print Dumper \%+;

通过使用命名捕获,我们确定a来自捕获组。不幸的是,当你通过split执行此操作时似乎没有填充 - 这可能会导致两遍方法。

这是我最接近的:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;

my $str = '123aaaa23a3';

#build a regex out of '2-or-more' characters. 
my $regex = join ( "|", map { $_."{2,}"} $str =~ m/([[:alpha:]])\1+/g);
#make the regex non-capturing
$regex = qr/(?:$regex)/;
print "Using: $regex\n";

#split on the regex
my @s  = split m/$regex/, $str;

print Dumper \@s;

我们首先处理字符串以提取“2或更多”字符模式,以设置为我们的delmiters。然后我们使用非捕获来组装正则表达式,因此我们可以拆分。

答案 1 :(得分:2)

一种解决方案是使用您原来的split电话并丢弃其他所有值。方便的是,List::Util::pairkeys是一个函数,它将每对值中的第一个保留在其输入列表中:

use List::Util 1.29 qw( pairkeys );

my @vals = pairkeys split /([[:alpha:]])\1+/, '123aaaa23a3';

给出

Odd number of elements in pairkeys at (eval 6) line 1.
[ '123', '23a3' ]

该警告来自pairkeys想要一个大小合适的列表的事实。我们可以通过在最后添加一个值来解决这个问题:

my @vals = pairkeys split( /([[:alpha:]])\1+/, '123aaaa23a3' ), undef;

另外,也许有点整洁,就是在列表的开头添加额外的值,然后使用pairvalues代替:

use List::Util 1.29 qw( pairvalues );

my @vals = pairvalues undef, split /([[:alpha:]])\1+/, '123aaaa23a3';

答案 2 :(得分:0)

通过在正则表达式中使用延迟执行断言(也称为推迟的常规子表达式)(??{ code }),可以使'split'直接工作:

@s = split /[[:alpha:]](??{"$&+"})/, '123aaaa23a3';

(??{ code })记录在'perlre'手册页上。

请注意,根据'perlvar'手册页,在程序中的任何位置使用$&会对所有正则表达式匹配造成相当大的性能损失。我从来没有发现这是一个问题,但是YMMV。