line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Lingua::DetectCyrillic;
|
2
|
|
|
|
|
|
|
# Нужно для перекодировки. Будет заменено в следующих выпусках
|
3
|
2
|
|
|
2
|
|
77670
|
use Unicode::Map8;
|
|
2
|
|
|
|
|
16180
|
|
|
2
|
|
|
|
|
214
|
|
4
|
2
|
|
|
2
|
|
2403
|
use Unicode::String;
|
|
2
|
|
|
|
|
16921
|
|
|
2
|
|
|
|
|
137
|
|
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
26
|
use Exporter ();
|
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
104
|
|
7
|
|
|
|
|
|
|
@ISA = qw ( Exporter );
|
8
|
|
|
|
|
|
|
@EXPORT_OK = qw ( &toLowerCyr &toUpperCyr &TranslateCyr %RusCharset );
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# Увеличение словаря с 300 до 3000 слов практически ничего не дало:
|
12
|
|
|
|
|
|
|
# при распознавании koi8/windows разница была порядка 30.
|
13
|
|
|
|
|
|
|
# Активизируем словари и хэши
|
14
|
2
|
|
|
2
|
|
2727
|
use Lingua::DetectCyrillic::DictRus;
|
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
81
|
|
15
|
2
|
|
|
2
|
|
5139
|
use Lingua::DetectCyrillic::DictUkr;
|
|
2
|
|
|
|
|
11
|
|
|
2
|
|
|
|
|
97
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# Хеширование по 3 пришлось снять - оно дает в среднем в 5 раз
|
18
|
|
|
|
|
|
|
# лучший результат, но хэш нужен в те же 5-7 раз больше.
|
19
|
2
|
|
|
2
|
|
9326
|
use Lingua::DetectCyrillic::WordHash2Rus;
|
|
2
|
|
|
|
|
18
|
|
|
2
|
|
|
|
|
167
|
|
20
|
2
|
|
|
2
|
|
8471
|
use Lingua::DetectCyrillic::WordHash2Ukr;
|
|
2
|
|
|
|
|
16
|
|
|
2
|
|
|
|
|
10806
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
$VERSION = "0.02";
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Глобальные переменные
|
25
|
|
|
|
|
|
|
$FullStat=0;
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
######## Экспортируемые переменные
|
28
|
|
|
|
|
|
|
$RusCharset{'Upper'} = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯҐЄІЇЎ";
|
29
|
|
|
|
|
|
|
$RusCharset{'Lower'} = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяґєіїў";
|
30
|
|
|
|
|
|
|
$RusCharset{'All'}="АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюяҐґЄєІіЇїЎў«»“”–—№";
|
31
|
|
|
|
|
|
|
$RusCharset{'Ukrainian'}= "ҐґЄєІіЇї";
|
32
|
|
|
|
|
|
|
$RusCharset{'Punctuation'}="«»“”–—№";
|
33
|
|
|
|
|
|
|
### Конец экспортируемых переменных
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
### Экспортируемые функции
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub TranslateCyr {
|
38
|
25
|
|
|
25
|
0
|
415
|
my ($CodingIn, $CodingOut, $String) = @_;
|
39
|
25
|
|
|
|
|
27
|
my ($MapIn, $MapOut);
|
40
|
|
|
|
|
|
|
|
41
|
25
|
|
|
|
|
48
|
$CodingIn=lc ($CodingIn);
|
42
|
25
|
|
|
|
|
31
|
$CodingOut=lc ($CodingOut);
|
43
|
|
|
|
|
|
|
# Если входная и выходная кодировки совпадают, вернуть неизмененную строку
|
44
|
25
|
100
|
|
|
|
59
|
if ( $CodingIn eq $CodingOut ) { return $String; }
|
|
6
|
|
|
|
|
19
|
|
45
|
|
|
|
|
|
|
|
46
|
19
|
100
|
|
|
|
170
|
if ($CodingIn =~ /(1251|win)/) { $MapIn = Unicode::Map8 -> new("cp1251"); $CodingIn="cp1251"; } elsif
|
|
7
|
100
|
|
|
|
28
|
|
|
7
|
100
|
|
|
|
839
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
47
|
2
|
|
|
|
|
10
|
($CodingIn =~ /(koi8u|koi8-u)/) { $MapIn = Unicode::Map8 -> new("koi8-u"); $CodingIn="koi8-u"; } elsif
|
|
2
|
|
|
|
|
191
|
|
48
|
2
|
|
|
|
|
12
|
($CodingIn =~ /koi/) { $MapIn = Unicode::Map8 -> new("koi8-r"); $CodingIn="koi8-r"; } elsif
|
|
2
|
|
|
|
|
274
|
|
49
|
2
|
|
|
|
|
9
|
($CodingIn =~ /(dos|866|alt)/) { $MapIn = Unicode::Map8 -> new("cp866"); $CodingIn="cp866"; } elsif
|
|
2
|
|
|
|
|
196
|
|
50
|
2
|
|
|
|
|
9
|
($CodingIn =~ /(iso|8859-5)/) { $MapIn = Unicode::Map8 -> new("ISO_8859-5"); $CodingIn="ISO_8859-5"; } elsif
|
|
2
|
|
|
|
|
213
|
|
51
|
2
|
|
|
|
|
9
|
($CodingIn =~ /(mac|10007)/) { $MapIn = Unicode::Map8 -> new("cp10007"); $CodingIn="cp10007"; } elsif
|
|
2
|
|
|
|
|
289
|
|
52
|
2
|
|
|
|
|
3
|
($CodingIn =~ /(utf|uni)/) { $CodingIn="utf-8"; } else
|
53
|
0
|
|
|
|
|
0
|
{ return ""; } # Если не определили входную кодировку - выйти
|
54
|
|
|
|
|
|
|
|
55
|
19
|
100
|
|
|
|
373
|
if ($CodingOut =~ /(1251|win)/) { $MapOut = Unicode::Map8 -> new("cp1251"); $CodingOut="cp1251"; } elsif
|
|
13
|
100
|
|
|
|
82
|
|
|
13
|
100
|
|
|
|
2288
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
56
|
1
|
|
|
|
|
5
|
($CodingOut =~ /(koi8u|koi8-u)/) { $MapOut = Unicode::Map8 -> new("koi8-u"); $CodingOut="koi8-u"; } elsif
|
|
1
|
|
|
|
|
104
|
|
57
|
1
|
|
|
|
|
7
|
($CodingOut =~ /koi/) { $MapOut = Unicode::Map8 -> new("koi8-r"); $CodingOut="koi8-r"; } elsif
|
|
1
|
|
|
|
|
110
|
|
58
|
1
|
|
|
|
|
6
|
($CodingOut =~ /(dos|866|alt)/) { $MapOut = Unicode::Map8 -> new("cp866"); $CodingOut="cp866";} elsif
|
|
1
|
|
|
|
|
88
|
|
59
|
1
|
|
|
|
|
4
|
($CodingOut =~ /(iso|8859-5)/) { $MapOut = Unicode::Map8 -> new("ISO_8859-5"); $CodingOut="ISO_8859-5";} elsif
|
|
1
|
|
|
|
|
87
|
|
60
|
1
|
|
|
|
|
4
|
($CodingOut =~ /(mac|10007)/) { $MapOut = Unicode::Map8 -> new("cp10007"); $CodingOut="cp10007"; } elsif
|
|
1
|
|
|
|
|
90
|
|
61
|
1
|
|
|
|
|
2
|
($CodingOut =~ /(utf|uni)/) { $CodingOut="utf-8"; } else
|
62
|
0
|
|
|
|
|
0
|
{ return ""; } # Если не определили выходную кодировку - выйти
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# Из UTF-8 в 8-битовую кодировку
|
65
|
19
|
100
|
|
|
|
52
|
if ( $CodingIn eq "utf-8" ) {
|
66
|
2
|
|
|
|
|
30
|
$s=Unicode::String::utf8($String)->ucs2;
|
67
|
2
|
50
|
|
|
|
772
|
if ( $CodingOut eq "utf-8" ) { return $String; } else { return $MapOut->to8($s); }
|
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
21
|
|
68
|
|
|
|
|
|
|
}
|
69
|
|
|
|
|
|
|
# Из 8-битовой кодировки в UTF-8
|
70
|
17
|
100
|
|
|
|
516
|
if ( $CodingOut eq "utf-8" ) { return $MapIn->tou($String)->utf8; }
|
|
1
|
|
|
|
|
7
|
|
71
|
|
|
|
|
|
|
# Если это не utf-8, то перекодируем из 8-битовго набора в 8-битовый же
|
72
|
16
|
|
|
|
|
188
|
return $MapIn->recode8($MapOut,$String);
|
73
|
|
|
|
|
|
|
}
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub toLowerCyr {
|
76
|
1
|
|
|
1
|
0
|
511
|
my ($s, $SourceCoding ) = @_;
|
77
|
1
|
50
|
|
|
|
5
|
if ( $SourceCoding ) { $s = TranslateCyr ( $SourceCoding, "win", $s ) }
|
|
1
|
|
|
|
|
6
|
|
78
|
1
|
|
|
|
|
199
|
eval ("\$s =~ tr/A-Z$RusCharset{'Upper'}/a-z$RusCharset{'Lower'}/");
|
79
|
1
|
50
|
|
|
|
9
|
if ( $SourceCoding ) { $s = TranslateCyr ( "win", $SourceCoding, $s ) }
|
|
1
|
|
|
|
|
4
|
|
80
|
1
|
|
|
|
|
8
|
$s;
|
81
|
|
|
|
|
|
|
}
|
82
|
|
|
|
|
|
|
sub toUpperCyr {
|
83
|
1
|
|
|
1
|
0
|
3
|
my ($s, $SourceCoding ) = @_;
|
84
|
1
|
50
|
|
|
|
5
|
if ( $SourceCoding ) { $s = TranslateCyr ( $SourceCoding, "win", $s ) }
|
|
1
|
|
|
|
|
4
|
|
85
|
1
|
|
|
|
|
77
|
eval ("\$s =~ tr/a-z$RusCharset{'Lower'}/A-Z$RusCharset{'Upper'}/");
|
86
|
1
|
50
|
|
|
|
27
|
if ( $SourceCoding ) { $s = TranslateCyr ( "win", $SourceCoding, $s ) }
|
|
1
|
|
|
|
|
4
|
|
87
|
1
|
|
|
|
|
6
|
$s;
|
88
|
|
|
|
|
|
|
}
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
######## Конец экспортируемых переменных и функций
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub new
|
93
|
|
|
|
|
|
|
{
|
94
|
|
|
|
|
|
|
# Заполнили данные по умолчанию
|
95
|
1
|
|
|
1
|
0
|
747
|
%Args = ( MaxTokens => 100, DetectAllLang => 0 );
|
96
|
1
|
|
|
|
|
4
|
my $self = {};
|
97
|
1
|
|
|
|
|
4
|
shift;
|
98
|
|
|
|
|
|
|
# Зачитали аргументы - это глобальный хэш
|
99
|
1
|
|
|
|
|
6
|
%Args = @_;
|
100
|
|
|
|
|
|
|
|
101
|
1
|
|
|
|
|
5
|
@Codings = ( "win1251", "koi8r", "cp866", "utf", "iso", "mac" );
|
102
|
1
|
50
|
|
|
|
5
|
if ( $Args{DetectAllLang} ) {push @Codings, koi8u};
|
|
1
|
|
|
|
|
199
|
|
103
|
1
|
|
|
|
|
4
|
@InputData="";
|
104
|
|
|
|
|
|
|
|
105
|
1
|
|
|
|
|
9
|
return bless ($self);
|
106
|
|
|
|
|
|
|
}
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub LogWrite {
|
110
|
1
|
|
|
1
|
0
|
2
|
shift;
|
111
|
1
|
|
|
|
|
2
|
my $Outfile=shift;
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
########### Формат отчета ##########
|
114
|
|
|
|
|
|
|
format STAT =
|
115
|
|
|
|
|
|
|
@<<<<<<@######@######@######@######@######@##########@##########@######@######
|
116
|
|
|
|
|
|
|
$key,%Stat->{$key}{GoodTokensChars},%Stat->{$key}{GoodTokensCount},%Stat->{$key}{AllTokensChars},%Stat->{$key}{AllTokensCount},%Stat->{$key}{CharsUkr},%Stat->{$key}{HashScore2Rus},%Stat->{$key}{HashScore2Ukr},%Stat->{$key}{WordsRus},%Stat->{$key}{WordsUkr}
|
117
|
|
|
|
|
|
|
.
|
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# Выводим отчет. Если названия файла нет, или это stdout - выводим на экран, иначе в файл
|
120
|
1
|
50
|
33
|
|
|
11
|
if (!$Outfile or uc ($Outfile) eq "STDOUT") {
|
121
|
0
|
|
|
|
|
0
|
$OUT=\*STDOUT;
|
122
|
|
|
|
|
|
|
} else {
|
123
|
1
|
|
|
|
|
125
|
open $OUT, ">$Outfile";
|
124
|
|
|
|
|
|
|
}
|
125
|
|
|
|
|
|
|
|
126
|
1
|
|
|
|
|
5
|
select $OUT; $~="STAT";
|
|
1
|
|
|
|
|
6
|
|
127
|
1
|
|
|
|
|
12
|
print "Coding: $Coding Language: $Language Algorithm: $Algorithm \n\n";
|
128
|
1
|
|
|
|
|
3
|
print " GdChr GdCnt AllChr AllCnt ChrUkr HashRus HashUkr WRus WUkr\n";
|
129
|
1
|
|
|
|
|
3
|
print "*" x 78 ."\n";
|
130
|
1
|
|
|
|
|
9
|
foreach $key (keys %Stat) { write ; }
|
|
7
|
|
|
|
|
15
|
|
131
|
1
|
|
|
|
|
2
|
print "*" x 78 ."\n";
|
132
|
1
|
|
|
|
|
153
|
print "Time: " .localtime() ."\n";
|
133
|
1
|
|
|
|
|
2
|
print <
|
134
|
|
|
|
|
|
|
GoodTokensChars - number of characters in pure Cyrillic tokens with correct
|
135
|
|
|
|
|
|
|
capitalization.
|
136
|
|
|
|
|
|
|
GoodTokensCount - number of pure Cyrillic tokens with correct capitalization.
|
137
|
|
|
|
|
|
|
AllTokensChars - number of characters in tokens containing Cyrillica.
|
138
|
|
|
|
|
|
|
AllTokensCount - their number
|
139
|
|
|
|
|
|
|
CharsUkr - number of Ukrainian letters
|
140
|
|
|
|
|
|
|
HashScore2Rus (Ukr) - hits on 2-letter hash
|
141
|
|
|
|
|
|
|
WordsRus (Ukr) - hits on frequency dictionary
|
142
|
|
|
|
|
|
|
POD
|
143
|
|
|
|
|
|
|
|
144
|
1
|
|
|
|
|
4
|
select STDOUT;
|
145
|
1
|
50
|
|
|
|
8
|
if ( $OUT ne \*STDOUT ) { close $OUT; }
|
|
1
|
|
|
|
|
138
|
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
} # LogWrite()
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub Detect {
|
151
|
1
|
|
|
1
|
0
|
2
|
shift;
|
152
|
|
|
|
|
|
|
# Перегружаем в глобальный массив @InputData, он может понадобиться еще раз
|
153
|
|
|
|
|
|
|
# при получении расширенной статистики.
|
154
|
|
|
|
|
|
|
|
155
|
1
|
|
|
|
|
4
|
@InputData = @_;
|
156
|
|
|
|
|
|
|
######## Отладочно сливаем ввод в файл
|
157
|
|
|
|
|
|
|
#$Outfile = "C:\\test_out3.txt";
|
158
|
|
|
|
|
|
|
#open OUT, ">$Outfile";
|
159
|
|
|
|
|
|
|
#for (@_) { print OUT; }
|
160
|
|
|
|
|
|
|
#close OUT;
|
161
|
|
|
|
|
|
|
########
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
|
164
|
1
|
|
|
|
|
4
|
_GetStat();
|
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# Теперь выясняем кодировку
|
167
|
1
|
|
|
|
|
2
|
$Language = ""; $Coding="";
|
|
1
|
|
|
|
|
3
|
|
168
|
1
|
|
|
|
|
2
|
$Algorithm=0; # Это примененная схема определения кодировки
|
169
|
1
|
|
|
|
|
1
|
$MaxCharsProcessed =0;
|
170
|
1
|
|
|
|
|
5
|
_AnalyzeStat();
|
171
|
1
|
50
|
|
|
|
17
|
if ( $Coding eq "win1251" ) { $Coding = "windows-1251" }
|
|
0
|
50
|
|
|
|
0
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
172
|
0
|
|
|
|
|
0
|
elsif ( $Coding eq "koi8r" ) { $Coding = "koi8-r" }
|
173
|
0
|
|
|
|
|
0
|
elsif ( $Coding eq "koi8u" ) { $Coding = "koi8-u" }
|
174
|
0
|
|
|
|
|
0
|
elsif ( $Coding eq "iso" ) { $Coding = "iso-8859-5" }
|
175
|
0
|
|
|
|
|
0
|
elsif ( $Coding eq "cp866" ) { $Coding = "cp866" }
|
176
|
0
|
|
|
|
|
0
|
elsif ( $Coding eq "utf" ) { $Coding = "utf-8" }
|
177
|
0
|
|
|
|
|
0
|
elsif ( $Coding eq "mac" ) { $Coding = "x-mac-cyrillic" }
|
178
|
1
|
|
|
|
|
3
|
else { $Coding = "iso-8859-1" }
|
179
|
|
|
|
|
|
|
|
180
|
1
|
|
|
|
|
12
|
return ( $Coding, $Language, $MaxCharsProcessed, $Algorithm );
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
}
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub _GetStat {
|
185
|
|
|
|
|
|
|
# Инициализируем структуру хэшей (описание см. в конце)
|
186
|
|
|
|
|
|
|
|
187
|
2
|
|
|
2
|
|
7
|
for (@Codings) {
|
188
|
14
|
100
|
|
|
|
30
|
if ( $FullStat ) {
|
189
|
7
|
|
|
|
|
14
|
$Stat{$_}{AllTokensChars} = 0;
|
190
|
7
|
|
|
|
|
11
|
$Stat{$_}{AllTokensCount} = 0;
|
191
|
7
|
|
|
|
|
10
|
$Stat{$_}{CharsUkr} = 0;
|
192
|
7
|
|
|
|
|
10
|
$Stat{$_}{HashScore2Rus} = 0;
|
193
|
7
|
|
|
|
|
14
|
$Stat{$_}{HashScore2Ukr} = 0;
|
194
|
7
|
|
|
|
|
14
|
$Stat{$_}{WordsRus} = 0;
|
195
|
7
|
|
|
|
|
14
|
$Stat{$_}{WordsUkr} = 0;
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
} else { # $FullStat
|
198
|
|
|
|
|
|
|
|
199
|
7
|
|
|
|
|
22
|
$Stat{$_}{GoodTokensChars} = 0;
|
200
|
7
|
|
|
|
|
13
|
$Stat{$_}{GoodTokensCount} = 0;
|
201
|
7
|
|
|
|
|
13
|
$Stat{$_}{CharsUkr} = 0;
|
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
} # $FullStat
|
204
|
|
|
|
|
|
|
} # end for
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# Получаем статистику для каждой строки
|
208
|
2
|
|
|
|
|
4
|
$EnoughTokens=0;
|
209
|
2
|
|
|
|
|
6
|
for ( @InputData ) {
|
210
|
2
|
|
|
|
|
3
|
my $String=$_;
|
211
|
|
|
|
|
|
|
|
212
|
2
|
|
|
|
|
4
|
for (@Codings) {
|
213
|
14
|
|
|
|
|
38
|
_ParseString ($_,$String,%Stat->{$_});
|
214
|
|
|
|
|
|
|
# Выходим, если хоть по одной из кодировок набрали максимальное число токенов
|
215
|
14
|
50
|
|
|
|
55
|
if (%Stat->{$_}{GoodTokensCount} > $Args{MaxTokens} ) { $EnoughTokens=1; }
|
|
0
|
|
|
|
|
0
|
|
216
|
|
|
|
|
|
|
}
|
217
|
|
|
|
|
|
|
|
218
|
2
|
50
|
|
|
|
11
|
if ( $EnoughTokens ) { last; }
|
|
0
|
|
|
|
|
0
|
|
219
|
|
|
|
|
|
|
} # Конец получения статистики
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
}
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
sub _AnalyzeStat {
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Сначала анализируем соотношение букв в чисто кириллических токенах
|
227
|
|
|
|
|
|
|
# с правильной капитализацией
|
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
## Анализируем формальную статистику по токенам с кириллицей
|
231
|
|
|
|
|
|
|
# Минимальное соотношение токенов с правильной капитализацией, при котором
|
232
|
|
|
|
|
|
|
# разницу считаем значимой для вычисления результата. Пока не используется.
|
233
|
|
|
|
|
|
|
# my $TokensRatio=0.95;
|
234
|
|
|
|
|
|
|
# Минимальный процент токенов с украинскими символами, чтобы текст считался украинским
|
235
|
1
|
|
|
1
|
|
3
|
my $UkrTokensShare=0.01;
|
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
## Анализируем чисто кириллические токены с правильной капитализацией.
|
238
|
1
|
|
|
|
|
2
|
my @CyrCharRating;
|
239
|
1
|
|
|
|
|
3
|
for ( @Codings ) { push @CyrCharRating,[$_, %Stat->{$_}{GoodTokensChars}]; }
|
|
7
|
|
|
|
|
23
|
|
240
|
1
|
|
|
|
|
8
|
@CyrCharRating = sort { $b->[1] <=> $a->[1] } @CyrCharRating;
|
|
11
|
|
|
|
|
16
|
|
241
|
|
|
|
|
|
|
|
242
|
1
|
|
|
|
|
3
|
$MaxCharsProcessed = $CyrCharRating[0]->[1];
|
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
# После сортировки получаем список наиболее вероятных кодировок
|
245
|
|
|
|
|
|
|
# Они содержат максимальное число "правильных" кириллических слов в данной кодировке
|
246
|
|
|
|
|
|
|
# Выясняем, между сколькими кодировками нужно провести различие
|
247
|
1
|
|
|
|
|
2
|
my @BestCodings;
|
248
|
1
|
|
|
|
|
3
|
for $arrayref ( @CyrCharRating ) {
|
249
|
7
|
50
|
|
|
|
15
|
if ( $arrayref ->[1] == $CyrCharRating[0]->[1] ) {
|
250
|
7
|
|
|
|
|
14
|
push @BestCodings, $arrayref ->[0] ;
|
251
|
|
|
|
|
|
|
}
|
252
|
|
|
|
|
|
|
}
|
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
# Если первая возможная кодировка содержит больше правильных символов,
|
255
|
|
|
|
|
|
|
# чем любая иная, считаем, что дело сделано. Вообще здесь лучше ввести
|
256
|
|
|
|
|
|
|
# определение минимально необходимого преимущества, скажем, 10% или что-то вроде.
|
257
|
|
|
|
|
|
|
|
258
|
1
|
50
|
|
|
|
5
|
if ( scalar(@BestCodings) == 1 ) {
|
259
|
0
|
|
|
|
|
0
|
$Coding = $CyrCharRating[0]->[0];
|
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
# Определяем язык. Смотрим, нет ли украинских токенов. Если они присутствуют
|
262
|
|
|
|
|
|
|
# в количестве не менее $UkrTokensShare, считаем язык украинским, иначе - русским.
|
263
|
0
|
0
|
|
|
|
0
|
if ( %Stat->{$Coding}{CharsUkr} / %Stat->{$Coding}{GoodTokensCount} > $UkrTokensShare )
|
264
|
0
|
|
|
|
|
0
|
{ $Language = "Ukr"; } else { $Language = "Rus"; }
|
|
0
|
|
|
|
|
0
|
|
265
|
0
|
|
|
|
|
0
|
$Algorithm = 11;
|
266
|
0
|
|
|
|
|
0
|
return;
|
267
|
|
|
|
|
|
|
} # Конец разбора одной кодировки
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Следующий вариант: одинаковое число баллов набрали ровно две кодировки.
|
270
|
|
|
|
|
|
|
# Не исключено, что это либо koi русский и украинский, либо win1251 и мас.
|
271
|
|
|
|
|
|
|
# Тогда мы их можем различить по формальным параметрам.
|
272
|
1
|
50
|
|
|
|
5
|
if ( scalar(@BestCodings) == 2 ) {
|
273
|
|
|
|
|
|
|
|
274
|
0
|
|
|
|
|
0
|
$BestCoding1 = $CyrCharRating[0]->[0];
|
275
|
0
|
|
|
|
|
0
|
$BestCoding2 = $CyrCharRating[1]->[0];
|
276
|
|
|
|
|
|
|
# Первый вариант - это кодировки koi8u и koi8r.
|
277
|
0
|
0
|
0
|
|
|
0
|
if ( $BestCoding1 =~ /koi/ && $BestCoding2 =~ /koi/ ) {
|
278
|
|
|
|
|
|
|
# Определяем язык и на этом основании - кодировку
|
279
|
0
|
0
|
0
|
|
|
0
|
if (%Stat->{$Coding}{GoodTokensCount} > 0 && %Stat->{$Coding}{CharsUkr} / %Stat->{$Coding}{GoodTokensCount} > $UkrTokensShare )
|
280
|
0
|
|
|
|
|
0
|
{ $Coding = "koi8u"; $Language = "Ukr"; } else { $Coding = "koi8r"; $Language = "Rus"; }
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
281
|
0
|
|
|
|
|
0
|
$Algorithm = 21;
|
282
|
0
|
|
|
|
|
0
|
return;
|
283
|
|
|
|
|
|
|
} # Конец 1-го варианта
|
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# Второй вариант - это кодировки win1251 и mac. То есть весь текст записан
|
286
|
|
|
|
|
|
|
# строчными буквами без Ю и Э. Предпочитаем однозначно win1251
|
287
|
0
|
0
|
0
|
|
|
0
|
if ( $BestCoding1 =~ /(win1251|mac)/ && $BestCoding2 =~ /(win1251|mac)/ ) {
|
288
|
0
|
|
|
|
|
0
|
$Coding="win1251";
|
289
|
0
|
0
|
0
|
|
|
0
|
if (%Stat->{$Coding}{GoodTokensCount} > 0 && %Stat->{$Coding}{CharsUkr} / %Stat->{$Coding}{GoodTokensCount} > $UkrTokensShare )
|
290
|
0
|
|
|
|
|
0
|
{ $Language = "Ukr"; } else { $Language = "Rus"; }
|
|
0
|
|
|
|
|
0
|
|
291
|
0
|
|
|
|
|
0
|
$Algorithm = 22;
|
292
|
0
|
|
|
|
|
0
|
return;
|
293
|
|
|
|
|
|
|
} # Конец 2-го варианта
|
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
} # Конец разбора двух кодировок при котором когда мы еще можем обойтись только анализом
|
296
|
|
|
|
|
|
|
# "правильных" символов, без привлечения расширенной статистики
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
# Итак, кодировку с ходу не удалось определить по статистике символов с правильной
|
299
|
|
|
|
|
|
|
# капитализацией. Тогда устанавливаем флаг $FullStat и еще раз получаем статистику по
|
300
|
|
|
|
|
|
|
# строкам - на этот раз с хэшем и словарем
|
301
|
1
|
|
|
|
|
2
|
$FullStat = 1;
|
302
|
1
|
|
|
|
|
3
|
_GetStat();
|
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# Проверяем, а есть ли кириллица в тексте вообще.
|
305
|
1
|
|
|
|
|
3
|
for ( @BestCodings ) { push @CyrCharRating,[$_, %Stat->{$_}{AllTokensChars}]; }
|
|
7
|
|
|
|
|
24
|
|
306
|
1
|
|
|
|
|
5
|
@CyrCharRating = sort { $b->[1] <=> $a->[1] } @CyrCharRating;
|
|
29
|
|
|
|
|
35
|
|
307
|
|
|
|
|
|
|
|
308
|
1
|
|
|
|
|
3
|
$MaxCharsProcessed = $CyrCharRating[0]->[1];
|
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
# Выйти, если не было ни одного кириллического символа
|
311
|
1
|
50
|
|
|
|
4
|
if ( $MaxCharsProcessed == 0 ) { $Coding = "iso-8859-1"; $Language = "NoLang"; $Algorithm = 100; return; }
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
# Делаем следующие два шага. Сначала создаем массив из комбинаций языка и кодировки
|
315
|
|
|
|
|
|
|
# для подсчета слов из словаря, затем оставляем только комбинации с максимальным значением,
|
316
|
|
|
|
|
|
|
# т.е. сужаем список потенциальных комбинаций. Если этих комбинаций больше одной,
|
317
|
|
|
|
|
|
|
# переходим ко второму шагу - создаем аналогичный массив для хэшей и снова отбираем
|
318
|
|
|
|
|
|
|
# комбинации с максимальным значением. Если снова не удалось выделить единственного
|
319
|
|
|
|
|
|
|
# "победителя", предпочитаем русский язык украинскому, кодировку windows - макинтошу.
|
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
# Шаг 1. Ищем максимальный рейтинг слов из частотного словаря
|
322
|
0
|
|
|
|
|
0
|
my @WordsRating;
|
323
|
0
|
|
|
|
|
0
|
for ( @BestCodings ) {
|
324
|
0
|
|
|
|
|
0
|
push @WordsRating, [$_,"Rus", %Stat->{$_}{WordsRus}];
|
325
|
0
|
|
|
|
|
0
|
push @WordsRating, [$_,"Ukr", %Stat->{$_}{WordsUkr}];
|
326
|
|
|
|
|
|
|
}
|
327
|
0
|
|
|
|
|
0
|
@WordsRating = sort { $b->[2] <=> $a->[2] } @WordsRating;
|
|
0
|
|
|
|
|
0
|
|
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
#print "WordsRating: \n";
|
330
|
|
|
|
|
|
|
#for $arrayref (@WordsRating) {
|
331
|
|
|
|
|
|
|
# print " " . $arrayref ->[0] . " " .$arrayref ->[1] ." ".$arrayref ->[2] ."\n"; }
|
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# Если обнаружили в тексте хотя бы одно слово из словаря, и нет альтернатив,
|
335
|
|
|
|
|
|
|
# то считаем, что определение языка/кодировки произошло
|
336
|
0
|
0
|
0
|
|
|
0
|
if ( $WordsRating[0]->[2] > 0 && $WordsRating[0]->[2] > $WordsRating[1]->[2] ) {
|
337
|
0
|
|
|
|
|
0
|
$Coding = $WordsRating[0]->[0];
|
338
|
0
|
|
|
|
|
0
|
$Language = $WordsRating[0]->[1];
|
339
|
0
|
|
|
|
|
0
|
$Algorithm = 31;
|
340
|
0
|
|
|
|
|
0
|
return;
|
341
|
|
|
|
|
|
|
}
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
# Либо слова из частотного словаря вообще не были обнаружены,
|
344
|
|
|
|
|
|
|
# либо имеем совпадение числа слов для нескольких комбинаций язык/кодировка
|
345
|
|
|
|
|
|
|
# Шаг 2. Обращаемся к хэшу и еще больше сужаем ареал поиска.
|
346
|
|
|
|
|
|
|
|
347
|
0
|
|
|
|
|
0
|
my @BestWordsRating;
|
348
|
0
|
|
|
|
|
0
|
for $arrayref ( @WordsRating ) {
|
349
|
0
|
0
|
|
|
|
0
|
if ( $arrayref ->[2] == $WordsRating[0]->[2] ) {
|
350
|
0
|
|
|
|
|
0
|
push @BestWordsRating, [ $arrayref ->[0],$arrayref ->[1],$arrayref ->[2] ] ;
|
351
|
|
|
|
|
|
|
}
|
352
|
|
|
|
|
|
|
}
|
353
|
|
|
|
|
|
|
#print "BestWordsRating: \n";
|
354
|
|
|
|
|
|
|
#for $arrayref (@BestWordsRating) {
|
355
|
|
|
|
|
|
|
# print " " . $arrayref ->[0] . " " .$arrayref ->[1] ." ".$arrayref ->[2] ."\n"; }
|
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
|
358
|
0
|
|
|
|
|
0
|
my @HashRating;
|
359
|
0
|
|
|
|
|
0
|
for $arrayref ( @BestWordsRating ) {
|
360
|
|
|
|
|
|
|
|
361
|
0
|
0
|
|
|
|
0
|
if ( $arrayref->[1] eq "Rus" ) {
|
362
|
0
|
|
|
|
|
0
|
push @HashRating, [$arrayref->[0],"Rus", %Stat->{$arrayref->[0]}{HashScore2Rus}]; }
|
363
|
0
|
0
|
|
|
|
0
|
if ( $arrayref->[1] eq "Ukr" ) {
|
364
|
0
|
|
|
|
|
0
|
push @HashRating, [$arrayref->[0],"Ukr", %Stat->{$arrayref->[0]}{HashScore2Ukr}]; }
|
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
}
|
367
|
0
|
|
|
|
|
0
|
@HashRating = sort { $b->[2] <=> $a->[2] } @HashRating;
|
|
0
|
|
|
|
|
0
|
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
#for $arrayref (@HashRating) {
|
370
|
|
|
|
|
|
|
# print " " .$arrayref ->[0] . " " .$arrayref ->[1] ." ".$arrayref ->[2] ."\n"; }
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
# Если обнаружили в тексте хотя бы один реальный хэш, и нет альтернатив,
|
373
|
|
|
|
|
|
|
# то считаем, что определение языка/кодировки произошло
|
374
|
0
|
0
|
0
|
|
|
0
|
if ( $HashRating[0]->[2] > 0 && $HashRating[0]->[2] > $HashRating[1]->[2] ) {
|
375
|
0
|
|
|
|
|
0
|
$Coding = $HashRating[0]->[0];
|
376
|
0
|
|
|
|
|
0
|
$Language = $HashRating[0]->[1];
|
377
|
0
|
|
|
|
|
0
|
$Algorithm = 32;
|
378
|
0
|
|
|
|
|
0
|
return;
|
379
|
|
|
|
|
|
|
}
|
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
# Либо хэш не обнаружен, либо имеем совпадение числа слов для нескольких комбинаций
|
383
|
|
|
|
|
|
|
# язык/кодировка
|
384
|
|
|
|
|
|
|
# Шаг 3. Оставляем только те комбинации язык/кодировка, которые содержат наибольшее число
|
385
|
|
|
|
|
|
|
# попаданий в хэш.
|
386
|
|
|
|
|
|
|
|
387
|
0
|
|
|
|
|
0
|
my @BestHashRating;
|
388
|
0
|
|
|
|
|
0
|
for $arrayref ( @HashRating ) {
|
389
|
0
|
0
|
|
|
|
0
|
if ( $arrayref ->[2] == $HashRating[0]->[2] ) {
|
390
|
0
|
|
|
|
|
0
|
push @BestHashRating, [ $arrayref ->[0],$arrayref ->[1] ] ;
|
391
|
|
|
|
|
|
|
}
|
392
|
|
|
|
|
|
|
}
|
393
|
|
|
|
|
|
|
# for $arrayref (@BestHashRating) {
|
394
|
|
|
|
|
|
|
# print " " .$arrayref ->[0] . " " .$arrayref ->[1] ." ".$arrayref ->[2] ."\n"; }
|
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# Теперь наступили тяжелые времена. ;-)) Остались только те комбинации кодировка/язык,
|
398
|
|
|
|
|
|
|
# для которых полностью совпадают данные и по частотному словарю, и по хэшу.
|
399
|
|
|
|
|
|
|
# Это может случиться ровно в двух случаях. Первый - весь текст набран строчными буквами.
|
400
|
|
|
|
|
|
|
# Тогда смешиваются Mac/Win. Предпочитаем Win.
|
401
|
|
|
|
|
|
|
# Второй - текст в koi набран без украинских букв. Тогда смешиваются koi8-r и koi8-u.
|
402
|
|
|
|
|
|
|
# Предпочитаем koi8-r (впрочем, разницы в данном случае никакой).
|
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
|
405
|
0
|
|
|
|
|
0
|
for $arrayref (@BestHashRating) {
|
406
|
0
|
0
|
|
|
|
0
|
if ( $arrayref ->[0] =~ /win/ ) {
|
407
|
0
|
|
|
|
|
0
|
$Coding = "win1251";
|
408
|
0
|
0
|
0
|
|
|
0
|
if (%Stat->{$Coding}{GoodTokensCount} > 0 && %Stat->{$Coding}{CharsUkr} / %Stat->{$Coding}{GoodTokensCount} > $UkrTokensShare )
|
409
|
0
|
|
|
|
|
0
|
{ $Language = "Ukr"; } else { $Language = "Rus"; }
|
|
0
|
|
|
|
|
0
|
|
410
|
0
|
|
|
|
|
0
|
$Algorithm = 33;
|
411
|
0
|
|
|
|
|
0
|
return;
|
412
|
|
|
|
|
|
|
}
|
413
|
|
|
|
|
|
|
}
|
414
|
|
|
|
|
|
|
|
415
|
0
|
|
|
|
|
0
|
for $arrayref (@BestHashRating) {
|
416
|
0
|
0
|
|
|
|
0
|
if ( $arrayref ->[0] =~ /koi/ ) {
|
417
|
0
|
|
|
|
|
0
|
$Coding = "koi8-r";
|
418
|
0
|
|
|
|
|
0
|
$Language = "Rus";
|
419
|
0
|
|
|
|
|
0
|
$Algorithm = 34;
|
420
|
0
|
|
|
|
|
0
|
return;
|
421
|
|
|
|
|
|
|
}
|
422
|
|
|
|
|
|
|
}
|
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# Ничего не подошло. Устанавливаем первую победившую кодировку и язык.
|
425
|
0
|
|
|
|
|
0
|
$Coding = $BestHashRating[0]->[0];
|
426
|
0
|
|
|
|
|
0
|
$Language = $BestHashRating[0]->[1];;
|
427
|
0
|
|
|
|
|
0
|
$Algorithm = 40;
|
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
|
430
|
0
|
|
|
|
|
0
|
return;
|
431
|
|
|
|
|
|
|
} #end _AnalyzeStat()
|
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
sub _ParseString {
|
437
|
14
|
|
|
14
|
|
27
|
my ($Coding, $String, $Hash) = @_;
|
438
|
|
|
|
|
|
|
# Перевели строку в кодировку win1251 и убрали знаки новой строки
|
439
|
14
|
|
|
|
|
31
|
$String = TranslateCyr($Coding,"win1251",$String);
|
440
|
14
|
|
|
|
|
34
|
$String =~ s/[\n\r]//go;
|
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
## Разбитие на слова
|
443
|
|
|
|
|
|
|
## \xAB\xBB - полиграфические кавычки, \x93\x94 - кавычки-"лапки",
|
444
|
|
|
|
|
|
|
## \xB9 - знак номера, \x96\x97 - полиграфические тире
|
445
|
14
|
|
|
|
|
192
|
for (split (/[\xAB\xBB\x93\x94\xB9\x96\x97\.\,\-\s\:\;\?\!\"\(\)\d<>]+/o, $String)) {
|
446
|
42
|
|
|
|
|
67
|
s/^\'+(.*)\'+$/$1/; # Убрали начальные и конечные апострофы
|
447
|
|
|
|
|
|
|
|
448
|
42
|
100
|
|
|
|
71
|
if ( !$FullStat ) {
|
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
# Определяем, "правильный" ли это токен, т.е. содержит только кириллицу
|
451
|
|
|
|
|
|
|
# и либо строчные буквы, либо ПРОПИСНЫЕ, либо начинается с Прописной.
|
452
|
21
|
50
|
33
|
|
|
867
|
if (/^[$RusCharset{'Lower'}]+$/ || /^[$RusCharset{'Upper'}]{1}[$RusCharset{'Lower'}]+$/ || /^[$RusCharset{'Upper'}]+$/ ) {
|
|
|
|
33
|
|
|
|
|
453
|
0
|
|
|
|
|
0
|
$$Hash{GoodTokensChars}+=length();
|
454
|
|
|
|
|
|
|
# Для UTF умножаем число кириллических символов на два.
|
455
|
0
|
0
|
|
|
|
0
|
if ( $Coding eq "utf" ) { $$Hash{GoodTokensChars}+=length(); }
|
|
0
|
|
|
|
|
0
|
|
456
|
0
|
|
|
|
|
0
|
$$Hash{GoodTokensCount}++;
|
457
|
|
|
|
|
|
|
# Если токен содержит украинские символы, увеличить счетчик украинских токенов
|
458
|
0
|
0
|
0
|
|
|
0
|
if ( $Args{DetectAllLang} && /[$RusCharset{'Ukrainian'}]/ ) { $$Hash{CharsUkr}++;}
|
|
0
|
|
|
|
|
0
|
|
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
}
|
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
} else { # !$FullStat
|
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
# Определяем, можно ли вообще проводить над этим токеном какие-либо действия.
|
465
|
|
|
|
|
|
|
# Для этого он должен содержать хотя бы одну правильную кириллическую букву,
|
466
|
|
|
|
|
|
|
# английские буквы и цифры в любой смеси.
|
467
|
21
|
50
|
33
|
|
|
252
|
if (/[$RusCharset{'All'}]/ && /^[\w\d$RusCharset{'All'}]+$/) {
|
468
|
0
|
|
|
|
|
|
$$Hash{AllTokensChars}+=length();
|
469
|
|
|
|
|
|
|
# Для UTF умножаем число символов на два.
|
470
|
0
|
0
|
|
|
|
|
if ( $Coding eq "utf" ) { $$Hash{AllTokensChars}+=length(); }
|
|
0
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# Если токен содержит украинские символы, увеличить счетчик украинских токенов
|
472
|
0
|
0
|
0
|
|
|
|
if ( $Args{DetectAllLang} && /[$RusCharset{'Ukrainian'}]/ ) { $$Hash{CharsUkr}++; }
|
|
0
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# Теперь приступаем к обработке хэша и словарей
|
475
|
|
|
|
|
|
|
# Переводим токен в нижний регистр - и словарь, и хэши у нас в нижнем регистре
|
476
|
0
|
|
|
|
|
|
$_=toLowerCyr($_);
|
477
|
|
|
|
|
|
|
|
478
|
0
|
0
|
|
|
|
|
if ($DictRus{$_}) { $$Hash{WordsRus}++; }
|
|
0
|
|
|
|
|
|
|
479
|
0
|
0
|
0
|
|
|
|
if ($Args{DetectAllLang} && $DictUkr{$_}) { $$Hash{WordsUkr}++; }
|
|
0
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
|
481
|
0
|
|
|
|
|
|
for $i (0..length()-1) {
|
482
|
0
|
0
|
|
|
|
|
if ( $WordHash2Rus{substr($_,$i,2)} ) { $$Hash{HashScore2Rus}++; }
|
|
0
|
|
|
|
|
|
|
483
|
0
|
0
|
0
|
|
|
|
if ( $Args{DetectAllLang} && $WordHash2Ukr{substr($_,$i,2)} ) { $$Hash{HashScore2Ukr}++; }
|
|
0
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
} # end for
|
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
} # end if (/^[\w\d$RusCharset{'All'}]+$/)
|
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
} # !$FullStat
|
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
} # end for (split...
|
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
} # end routine
|
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
1;
|
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
__END__
|