在 Perl 中,我试图从一段文本中构建一个包含所有单词的数组。
现在我正在使用@tokens = split /[^\w']+/, $mytext;
它似乎正在获取所有字母数字单词,但我希望所有标点符号都被视为除下划线之外的单词。例子
hi. my name is first_last ...
应该变成的话:hi , . , 我的 , 名字 , 是 , first_last , . , . , .
一共9个字。
我怎样才能做到这一点?我尝试拆分标点符号,但没有保存标点符号。
匹配往往比拆分容易;听起来您想匹配任何一系列单引号/单词字符(包括_)或任何其他非空白字符:
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'\-]
添加连字符)。
如果这是你的话
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;
扩展 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 不仅匹配标点符号。
以上显示了如何使用 | 拆分可以组成单词的字符集,并明确定义字符。不属于任何单词的“垃圾”会被过滤掉。
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), (.), (.), (.)
一种方法是使用环视断言:您想在空白处拆分 (1);(2) 每当前一个字符出现时[^\w']
(字符串结尾除外);(3) 每当下一个字符出现时[^\w']
(字符串开头除外),因此您可以编写:
@tokens = split /\s+|(?<=[^\w'])|(?=(?!^)[^\w'])/, $mytext;