拆分所有单词但保留拆分字符

时间:2013-01-31 18:45:47

标签: regex perl

在Perl中,我试图从一段文本构建一个包含所有单词的数组。

现在我正在使用@tokens = split /[^\w']+/, $mytext;

它似乎得到了所有的alphanum单词,但我希望所有的标点符号都被认为是一个单词,除了下划线。实施例

hi. my name is first_last ...

应该变成:嗨,。 ,我的名字,是,first_last ,. ,。 ,。

总共9个单词。

我该怎么做?我试着在标点符号上进行分割但是没有保存标点符号。

5 个答案:

答案 0 :(得分:2)

匹配比分开更容易;听起来你想要匹配任何系列的单引号/单词字符(包括_)或任何一个其他非空白字符:

my $mytext = 'hi. my name is first_last ...';
my @tokens = $mytext =~ /([\w']+|\S)/g;
print join( ' , ',  @tokens ),"\n";

产生

hi , . , my , name , is , first_last , . , . , .

[\w']是一个允许任何单词字符(字母,数字或下划线)或单引号的字符类;可以添加其他字符,但有些可能需要\ _escaped(例如[\w'\-]添加连字符)。

答案 1 :(得分:1)

如果这些是你的话

hi. my name is first_last ...
11  22 3333 44 5555555555

这些不是你的分隔符

hi. my name is first_last ...
  11  22   33 4          5555

那么你实际上并没有分裂单词(而split可能效果不好)。你实际上需要一个tokeniser。

以下是构建令牌器的一般方法:

my @tokens;
for ($mytext) {
   /\G \s+ /xgc;
   if (/\G ( [\w']+   ) /xgc) { push @tokens, $1; redo; }
   if (/\G ( [^\s\w'] ) /xgc) { push @tokens, $1; redo; }
   die "Bad code";
}

但我们可以简化它。

my @tokens = $mytext =~ /\G\s*([\w']+|[^\S\w'])/g;

甚至

my @tokens = $mytext =~ /\G\s*([\w']+|\S)/g;

答案 2 :(得分:0)

一种方法是使用lookaround assertions:你想在空格上拆分(1); (2)每当前一个字符在[^\w']时(除了字符串结尾); (3)每当下一个字符在[^\w']时(字符串开头除外),所以你可以写:

@tokens = split /\s+|(?<=[^\w'])|(?=(?!^)[^\w'])/, $mytext;

答案 3 :(得分:0)

perldoc -f split 
==>
    split /PATTERN/,EXPR,LIMIT
    split /PATTERN/,EXPR
    split /PATTERN/
    split   Splits the string EXPR into a list of strings and returns that
            list. By default, empty leading fields are preserved, and empty
            trailing ones are deleted. (If all fields are empty, they are
            considered to be trailing.)
    ...
            If the PATTERN contains parentheses, additional list elements
            are created from each matching substring in the delimiter.

                split(/([,-])/, "1-10,20", 3);

            produces the list value

                (1, '-', 10, ',', 20)
    ...

增加:

在代码中:

my $inp   = 'hi. my name is first_last ...';
my @parts = split /(\W)/, $inp;
printf "%d parts: (%s)\n", scalar @parts, join('), (', @parts);
@parts = grep {$_ gt ' '} @parts;
printf "%d parts: (%s)\n", scalar @parts, join('), (', @parts);

输出:

18 parts: (hi), (.), (), ( ), (my), ( ), (name), ( ), (is), ( ), (first_last), ( ), (), (.), (), (.), (), (.)
9 parts: (hi), (.), (my), (name), (is), (first_last), (.), (.), (.)

答案 4 :(得分:0)

扩展ysth的想法:

my $mytext = 'hi. My name22222 is first_last!? 2,0 #@/';
my @tokens = $mytext =~ /([a-zA-Z_]+|[0-9]+|[.?!,])/g;
print join ":", @tokens,"\n";

输出:

hi:.:My:name:22222:is:first_last:!:?:2:,:0:

这更容易理解,因为它避免使用\ w和\ S. \ w涵盖的内容比你想象的要多,因为它包含了_这令人困惑。 \ S也不仅仅是标点符号。

以上显示了如何使用|分割可组成单词的字符集,并明确定义字符。过滤掉不属于任何单词的“垃圾”。