Может ли человек сделать это?
farsidebag
far sidebag
farside bag
far side bag
Мало того, что вы должны использовать словарь, вам, возможно, придется использовать статистический подход, чтобы выяснить, что наиболее вероятно (или, не дай бог, фактический HMM для вашего человеческого языка по вашему выбору ...)
Для получения статистических данных, которые могут быть полезны, я обращаюсь к доктору Питеру Норвигу, который решает другую, но связанную с этим проблему проверки орфографии в 21 строке кода :
http://norvig.com/spell-correct.html
(он немного обманывает, складывая каждый цикл for в одну строку ... но все же).
Обновление Это застряло в моей голове, поэтому мне пришлось родить его сегодня. Этот код выполняет разделение, аналогичное описанному Робертом Гэмблом, но затем он упорядочивает результаты на основе частоты слов в предоставленном файле словаря (который теперь, как ожидается, будет некоторым текстовым представителем вашего домена или английского языка в целом. Я использовал большой .txt от Norvig, ссылка на которую приведена выше, и содержит словарь для покрытия пропущенных слов).
Комбинация из двух слов в большинстве случаев побьет комбинацию из 3 слов, если разница в частотах не огромна.
Я разместил этот код с некоторыми незначительными изменениями в своем блоге
http://squarecog.wordpress.com/2008/10/19/splitting-words-joined-into-a-single-string/
и также написал немного об ошибке недопустимости в этом коде. Я хотел просто спокойно ее исправить, но подумал, что это может помочь некоторым людям, которые раньше не видели трюк с журналом:
http://squarecog.wordpress.com/2009/01/10/dealing-with-underflow-in-joint-probability-calculations/
Вывод ваших слов, плюс несколько моих собственных - обратите внимание, что происходит с "orcore":
perl splitwords.pl big.txt words
answerveal: 2 possibilities
- answer veal
- answer ve al
wickedweather: 4 possibilities
- wicked weather
- wicked we at her
- wick ed weather
- wick ed we at her
liquidweather: 6 possibilities
- liquid weather
- liquid we at her
- li quid weather
- li quid we at her
- li qu id weather
- li qu id we at her
driveourtrucks: 1 possibilities
- drive our trucks
gocompact: 1 possibilities
- go compact
slimprojector: 2 possibilities
- slim projector
- slim project or
orcore: 3 possibilities
- or core
- or co re
- orc ore
Код:
#!/usr/bin/env perl
use strict;
use warnings;
sub find_matches($);
sub find_matches_rec($\@\@);
sub find_word_seq_score(@);
sub get_word_stats($);
sub print_results($@);
sub Usage();
our(%DICT,$TOTAL);
{
my( $dict_file, $word_file ) = @ARGV;
($dict_file && $word_file) or die(Usage);
{
my $DICT;
($DICT, $TOTAL) = get_word_stats($dict_file);
%DICT = %$DICT;
}
{
open( my $WORDS, '<', $word_file ) or die "unable to open $word_file\n";
foreach my $word (<$WORDS>) {
chomp $word;
my $arr = find_matches($word);
local $_;
# Schwartzian Transform
my @sorted_arr =
map { $_->[0] }
sort { $b->[1] <=> $a->[1] }
map {
[ $_, find_word_seq_score(@$_) ]
}
@$arr;
print_results( $word, @sorted_arr );
}
close $WORDS;
}
}
sub find_matches($){
my( $string ) = @_;
my @found_parses;
my @words;
find_matches_rec( $string, @words, @found_parses );
return @found_parses if wantarray;
return \@found_parses;
}
sub find_matches_rec($\@\@){
my( $string, $words_sofar, $found_parses ) = @_;
my $length = length $string;
unless( $length ){
push @$found_parses, $words_sofar;
return @$found_parses if wantarray;
return $found_parses;
}
foreach my $i ( 2..$length ){
my $prefix = substr($string, 0, $i);
my $suffix = substr($string, $i, $length-$i);
if( exists $DICT{$prefix} ){
my @words = ( @$words_sofar, $prefix );
find_matches_rec( $suffix, @words, @$found_parses );
}
}
return @$found_parses if wantarray;
return $found_parses;
}
## Just a simple joint probability
## assumes independence between words, which is obviously untrue
## that's why this is broken out -- feel free to add better brains
sub find_word_seq_score(@){
my( @words ) = @_;
local $_;
my $score = 1;
foreach ( @words ){
$score = $score * $DICT{$_} / $TOTAL;
}
return $score;
}
sub get_word_stats($){
my ($filename) = @_;
open(my $DICT, '<', $filename) or die "unable to open $filename\n";
local $/= undef;
local $_;
my %dict;
my $total = 0;
while ( <$DICT> ){
foreach ( split(/\b/, $_) ) {
$dict{$_} += 1;
$total++;
}
}
close $DICT;
return (\%dict, $total);
}
sub print_results($@){
#( 'word', [qw'test one'], [qw'test two'], ... )
my ($word, @combos) = @_;
local $_;
my $possible = scalar @combos;
print "$word: $possible possibilities\n";
foreach (@combos) {
print ' - ', join(' ', @$_), "\n";
}
print "\n";
}
sub Usage(){
return "$0 /path/to/dictionary /path/to/your_words";
}