Как посчитать китайское слово в файле с помощью регулярных выражений в Perl? - PullRequest
3 голосов
/ 06 января 2011

Я попробовал следующий код perl, чтобы посчитать китайское слово файла, оно работает, но не получается Любая помощь с благодарностью.

Сообщение об ошибке

Use of uninitialized value $valid in concatenation (.) or string at word_counting.pl line 21, <FILE> line 21.
Total things  = 125, valid words = 

что мне кажется проблема в формате файла. «Всего» 125 - это номер строки (125 строк). Самое странное, что моя консоль безошибочно отображает все отдельные китайские слова. Прагма utf-8 установлена.

#!/usr/bin/perl -w
use strict;
use utf8;
use Encode qw(encode);
use Encode::HanExtra;

my $input_file = "sample_file.txt";
my ($total, $valid);
my %count;

open (FILE, "< $input_file") or die "Can't open $input_file: $!";

while (<FILE>) {
 foreach (split) { #break $_ into words, assign each to $_ in turn
 $total++;
 next if /\W|^\d+/;  #strange words skip the remainder of the loop
 $valid++;
 $count{$_}++;  # count each separate word stored in a hash
 ## next comes here ##
      }
   }

   print "Total things  = $total, valid words = $valid\n";
   foreach my $word (sort keys %count) {
      print "$word \t was seen \t $count{$word} \t times.\n";
   }

##---Data----
sample_file.txt

那天约二更时,只见封肃方回来,欢天喜地.众人忙问端的.他乃说道:"原来本府新升的太爷姓贾名化,本贯胡州人氏,曾与女婿旧日相交.方才在咱门前过去,因见娇杏那丫头买线, 所以他只当女婿移住于此.我一一将原故回明,那太爷倒伤感叹息了一回,又问外孙女儿,我说看灯丢了.太爷说:`不妨,我自使番役务必探访回来.'说了一回话, 临走倒送了我二两银子."甄家娘子听了,不免心中伤感.一宿无话.至次日, 早有雨村遣人送了两封银子,四匹锦缎,答谢甄家娘子,又寄一封密书与封肃,转托问甄家娘子要那娇杏作二房. 封肃喜的屁滚尿流,巴不得去奉承,便在女儿前一力撺掇成了,乘夜只用一乘小轿,便把娇杏送进去了.雨村欢喜,自不必说,乃封百金赠封肃, 外谢甄家娘子许多物事,令其好生养赡,以待寻访女儿下落.封肃回家无话.

Ответы [ 2 ]

4 голосов
/ 06 января 2011

Мы устанавливаем STDOUT на : utf8 IO layer , чтобы оператор не отображал искаженные данные, затем открываем файл с тем же слоем, чтобы ромб не читал искаженные данные.Позже, в то время как вместо того, чтобы разбивать пустую строку, мы используем регулярное выражение с "East_Asian_Width: Wide" Unicode-подобным свойством .

utf8 для моей личной проверки работоспособностии может быть удален (Y).

use strict;
use warnings;
use 5.010;
use utf8;
use autodie;

binmode(STDOUT, ':utf8');

open my $fh, '<:utf8', 'sample_file.txt';

my ($total, $valid);
my %count;

while (<$fh>) {
    $total += length;
    for (/(\p{Ea=W})/g) {
        $valid++;
        $count{$_}++;
    }
}

say "Total things  = $total, valid words = $valid";
for my $word (sort keys %count) {
   say "$word \t was seen \t $count{$word} \t times.";
}

РЕДАКТИРОВАТЬ: J-16 SDiZ и Даксим указали, что шансы на sample_file.txt в UTF-8 очень малы.Прочитайте их комментарии, а затем взгляните на Модуль кодирования в perldoc, в частности, раздел «Кодирование через PerlIO».

2 голосов
/ 06 января 2011

Я могу предложить некоторую информацию, но трудно сказать, будет ли мой ответ «полезным».Во-первых, я только говорю и читаю по-английски, поэтому я явно не говорю и не читаю по-китайски.Я действительно являюсь автором RegexKitLite , который является оболочкой Objective-C для движка регулярных выражений ICU.Очевидно, это не perl,:).

Несмотря на это, в движке регулярных выражений ICU есть функция, которая поразительно похожа на то, что вы пытаетесь сделать.В частности, механизм регулярных выражений ICU содержит опцию модификатора UREGEX_UWORD, которую можно динамически включать с помощью обычного синтаксиса (?w:...).Этот модификатор выполняет следующее действие:

Управляет поведением \ b в шаблоне.Если установлено, границы слова находятся в соответствии с определениями слова, найденными в Unicode UAX 29, «Текстовые границы».По умолчанию границы слова идентифицируются с помощью простой классификации символов как «слово» или «не слово», что приблизительно соответствует традиционному поведению регулярного выражения.Результаты, полученные с помощью двух опций, могут сильно отличаться в серии пробелов и других несловарных символов.

Вы можете использовать это в регулярном выражении, например (?w:\b(.*?)\b), чтобы «извлечь» слова из строки,В движке регулярных выражений ICU он имеет довольно мощный «механизм разбиения по словам», который специально разработан для поиска разрывов слов в письменных языках, которые не имеют явного пробела «символ», такого как английский.Опять же, я не читаю и не пишу на этих языках, и я понимаю, что «это что-то вроде этого».В механизме прерывания слова ICU используется эвристика, а иногда и словари, чтобы найти разрывы слова.Насколько я понимаю, тайский язык - это особенно сложный случай.Фактически, я использую ฉันกินข้าว (по-тайски «я ем рис», или мне так сказали) с регулярным выражением (?w)\b\s* для выполнения операции split над строкой для извлечения слов.Без (?w) вы не можете разбить на разрывы слов.С (?w) это приводит к словам ฉัน, กิน и ข้าว.

Если приведенное выше «звучит как проблема, с которой вы столкнулись», то это может быть причиной.Если это так, то я не знаю ни одного способа сделать это в perl, но я бы не считал это мнение авторитетным ответом, так как я использую механизм регулярных выражений ICU чаще, чем perl, и яявно не правильно мотивированы, чтобы найти работающее perl решение, когда оно у меня уже есть :).Надеюсь, это поможет.

...