如果你想转换/翻译下面的代码行,是否有特定的库、算法或技术(除了使用正则表达式)可供使用。
"Acme Corporation Inc., John, Doe, F."
"Smith, Allen, Smith,Susan"
"Marshall, J., L., Johnson, H., Caruso, D., Jones, J."
"Stein, Harry, Joan, and Mike"应将这些行转换为包含以下内容的文本:
Acme {TAB} Corporation
Doe {TAB} John
Smith {TAB} Allen
Smith {TAB} Susan
Marshall {TAB} J.
Johnson {TAB} H.
Caruso {TAB} D.
Jones {TAB} J.
Stein {TAB} Harry
Stein {TAB} Joan
Stein {TAB} Mike原文只包含专有名称和中间首字母(D.或J)。除了偶尔用“和”分隔同名的同级,与上面最后一行原文相同。
另外,这是否被认为是“命名实体识别”,或者这个过程还有其他的技术名称?
理想情况下,我希望使用Ruby/Python/Perl/PHP等语言编写的代码或算法可以进行这种转换。
有什么想法吗?提前谢谢。
发布于 2012-01-03 23:12:23
这几乎是可行的:
#!/usr/bin/env perl
use strict;
use warnings;
my $tok = undef;
my @pairs = ();
my $looking_for = 'surname';
sub parse_line_to_words($){
my $l = shift;
my @words;
my $word = '';
my $start = 1;
# remove trailing newlines
chomp $l;
if(index($l, '"', -1) != -1){
# remove trailing quotation mark.
chop $l;
}
foreach my $c (split//,$l){
if($c eq '"'){
if($#words == -1){
# skip leading quotation marks
next;
}
}
if($c eq ','){
push(@words, $word);
$word = '';
$start = 1;
} else{
if($start && $c eq ' '){
next;
} else{
$start = 0;
}
$word .= $c;
}
}
if($word ne ''){
push(@words, $word);
}
return @words;
}
sub peek_and(@){
foreach my $word (@_){
return 1 if $word eq 'and'
}
return 0;
}
sub split_and(@){
my @copy;
foreach my $word (@_){
if(index($word, 'and ', 0) != -1){
my $i = index($word, 'and ', 0) + 4;
push(@copy, substr($word, 0, $i - 1));
push(@copy, substr($word, $i));
} else{
push(@copy, $word);
}
}
return @copy;
}
sub count_spaces($){
my $w = shift;
my $s=0;
for(my $p = index($w, ' ', 0); $p != -1; $p=index($w, ' ', $p+1), $s++) {}
return $s;
}
sub found($$$){
my $pairs = shift;
push(@{$pairs}, {'surname' => shift, 'firstname' => shift});
}
while(<>){
chomp;
my $line = $_;
my @words = parse_line_to_words($line);
@words = split_and(@words);
my $line_has_and = peek_and(@words);
foreach my $word (@words){
my $spaces = count_spaces($word);
if($looking_for eq 'surname'){
if(index($word, '.', -1) != -1 && $spaces == 0){
# looks like an initial to me, skip it
} else{
if($spaces > 0){
# multi-word token; must be corporation name
my($f, $l) = split(/ /, $word);
found(\@pairs, $f, $l);
} else{
$tok = $word;
$looking_for = 'firstname';
}
}
} elsif ($looking_for eq 'firstname'){
if($line_has_and){
# lastname, first1, ..., firstn and firstn+1
if($word ne 'and'){
found(\@pairs, $tok, $word);
}
} else{
# lastname, f. or lastname, firstname
found(\@pairs, $tok, $word);
$looking_for = 'surname';
}
}
}
$looking_for = 'surname'; # reset for new line
}
foreach my $p (@pairs){
printf("%s\t%s\n", $p->{'surname'}, $p->{'firstname'});
}给定样本输入的实际输出
Acme Corporation
John Doe
Smith Allen
Smith Susan
Marshall J.
Johnson H.
Caruso D.
Jones J.
Stein Harry
Stein Joan
Stein Mike讨论
我采用了以下启发式方法:
’开头,则应特殊处理整个行,其中第一个单词是姓氏,其余是对应的名字。
如果一个姓氏包含的空格超过0个,则它是corporation
最后,我使用“正则表达式”只是为了在空格上拆分公司名称;这可以用一个非正则表达式版本替代。
尽管如此,我仍然得到"John Doe“错误,因为它的名称在输入中是颠倒的。我想不出一个可靠的方法来检测这一点。
https://stackoverflow.com/questions/8712760
复制相似问题