0

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

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

它似乎正在获取所有字母数字单词,但我希望所有标点符号都被视为除下划线之外的单词。例子

hi. my name is first_last ...

应该变成的话:hi , . , 我的 , 名字 , 是 , first_last , . , . , .

一共9个字。

我怎样才能做到这一点?我尝试拆分标点符号,但没有保存标点符号。

4

5 回答 5

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']是允许任何单词字符(字母、数字或下划线)或单引号的字符类;可以添加其他字符,但有些可能需要转义(例如[\w'\-]添加连字符)。

于 2013-01-31T18:55:52.367 回答
1

如果这是你的话

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

这些不是你的分隔符

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

那么您实际上并没有拆分单词(并且split可能效果不佳)。你实际上需要一个标记器。

这是构建标记器的通用方法:

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;
于 2013-01-31T19:45:58.320 回答
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 不仅匹配标点符号。

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

于 2013-01-31T20:36:33.910 回答
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), (.), (.), (.)
于 2013-01-31T18:57:44.820 回答
0

一种方法是使用环视断言:您想在空白处拆分 (1);(2) 每当前一个字符出现时[^\w'](字符串结尾除外);(3) 每当下一个字符出现时[^\w'](字符串开头除外),因此您可以编写:

@tokens = split /\s+|(?<=[^\w'])|(?=(?!^)[^\w'])/, $mytext;
于 2013-01-31T18:50:03.923 回答