Универсальный код деления на предложения...

Статус
В этой теме нельзя размещать новые ответы.

System777

Создатель
Регистрация
20 Апр 2008
Сообщения
30
Реакции
13
Подкиньте, пожалуйста, если у кого есть универсальный код для деления любого (русского, но возможно с англ. терминами) текста на предложения.

Важен код для всех возможных случаев предложений:

1. Обычное предложение: Слово слово слово слово.

2. Восклицательные, вопросительные, с "...": Слово слово!

3. С встречающимися числами с точкой: Слово 22.1 слово.

4. С прямой речью: Слово сказал: "Это слово слово". и также Слово сказал: "Это слово слово?" (вопросительные - знак перед кавычкой).

5. В виде диалога:

- Привет, - сказал Вася.

6. Сложные и смешанные с терминами:

- "Это слово 22$ domain", - кто-то сказал (из наших), - "нужно понимать №22.33 правильно в Магадане!"

7. С учётом сокращений: Я живу в г. Москва!

8. В идеале - ещё бы определять предложения, где вместо символа конца ставят смайл :) или ещё что-то

Например:

Привет : ) Как дела?

Возможны и другие варианты, может я что-то не учёл...

Отдельные предложения потом будут дополнительно анализироваться, но важно чтобы они были отделены.

Заранее благодарю!
 
Как ты предполагаешь искать сокращения? 100% нельзя различить, где сокращение, а где конец предложения.

Ну это, в принципе, не критично, таких исходных текстов (с сокращениями) думаю, будет не так много. Остальные пункты важнее...

Также, как вариант, можно просто составить базу популярных сокращений - и потом либо определять, либо делать автозамену ;)
 
Прикольно , хотя и не без глюков. 'я' на конце предложения он считает за сокращение, например:
Привет, это я. Как дела?
посчитает за одно предложение. За одно предложение посчитает также:
Это город Москва.
Это памятник Ленину.

А еще могли бы отсекать неизвестные сокращения не в конце предоложения, если следующее слово с прописной буквы.
 
Прикольно , хотя и не без глюков. 'я' на конце предложения он считает за сокращение, например:
Привет, это я. Как дела?
посчитает за одно предложение.


У них же написано в TextParser.dot-reductions.txt
"#однобуквенные сокращения уже пропускаются!"
нужно порыться в коде, поискать где можно вставить исключения типа "я." :(

а вот с Москвой я не понял
 
Код от меня. Перловый.
Ток по смайлам пока не разбивает.
В отличии от парсера выше:
Прямую речь в кавычках и речь в скобках не разбивает.
"Ну что это такое!!! Как так можно???" - возмутился я
Однобуквенные сокращения пропускает, но букву 'я' учитывает, по ней разбивает.
Привет, это я. Как дела?
Если после сокращения слово начинается не с большой буквы, учитывает его. В противном случае проверяет слово по массиву.
Это сокр. от слова
Аналогично пропускает, если после многоточия нет заглавной буквы.
С осенних дубов облетает... цена!
Еще разбивает, если в конце предложения нет точки, но следующее начинается с новой строки и большой буквы (Хотя это может неправильно разбить если после переноса строки идет имя собственное, но таких случаев имхо куда меньше)
Тестим:)

Код:
#!/usr/bin/perl
use locale;
use POSIX qw(locale_h);
setlocale(LC_CTYPE,"ru_RU.CP1251");

$text=<<EOF;         #текст
Превед медвед
EOF

@sokr=('гр','бр');          #масив с сокращениями
$i=0;
#Строки формата Windows и Mac OS к формату Unix
$text=~s/\r\n/\n/;
$text=~s/\r/\n/;

@predl=$text=~m{(
\G(?:
    ([а-яa-z]++)|
    [^.\n?!а-яa-z\d("]++(?:[!\?]++)?|
    \.(?:\.*+)
       [^а-яa-z.?!\n]*+(?:\n[^а-яa-z.?!\n]*+)?
       (?=(?-i:[а-яa-z]))|
    (?<=\b[а-юa-z])\.|
    \.(?!\.)(?(?{while($i<@sokr && $sokr[$i] ne $2) {$i++;}; @sokr!=$i})|(?!))|
    \n[^а-яa-z.?!\n]*+(?=(?-i:[а-яa-z]))|
    \d++(?:\.\d++)?|
    (?:"(?=[^\s.]).*?(?<=[^\s])"|")|
    (?:\((?=[^\s.]).*?(?<=[^\s])\)|\( )
)+
[?!\n.]*
)}isxg;



if ($+[0]!=length($text)) {
   print "Ошибка разбора:\n";
   print $predl[-1],"[!]";
   print substr($text,$+[0], 20), "\n";
   print "-----------";
}

for ($i=0;$i<@predl;$i+=2) {
  $predl[$i]=~s/\n//;
  $predl[$i]=~s/^\s+//;
  $predl[$i]=~s/\s+$//;
  print $predl[$i],"\n";
}
 
Хотел адаптировать эти регулярные выражения для php, что то пока без успешно. Но могли бы помочь немножко
 
Напрямую не получится, т.к. в выражении используется встроенный код, а в PHP такой фитчи нет.
 
myphpcoder
По поводу PHP
Решение "в лоб", одной регуляркой
PHP:
$sokr='\b'.join('.|\b',$sokr).'.';
$re= '
{
\G(?:
    [а-яa-z]++|
    [^.\n?!а-яa-z\d("]++(?:[!\?]++)?|
    \.(?:\.*+)
       [^а-яa-z.?!\n]*+(?:\n[^а-яa-z.?!\n]*+)?
       (?=(?-i:[а-яa-z]))|
    (?<=\b[а-юa-z])\.|
    \.(?!\.)(?<='.$sokr.')|
    \n[^а-яa-z.?!\n]*+(?=(?-i:[а-яa-z]))|
    \d++(?:\.\d++)?|
    (?:("(?=[^\s.]).*?(?<=[^\s])"|"))|
    (?:\((?=[^\s.]).*?(?<=[^\s])\)|\( )
)+
[?!\n.]*
}isx';
Но при большой базе сокрашений это будет медленно.
Тогда, чтобы как в исходном примере, пробивать слово по массиву отдельно:
PHP:
$re='
{
\G(?:
    ([а-яa-z]++)|
    [^.\n?!а-яa-z\d("]++(?:[!\?]++)?|
    \.(?:\.*+)
       [^а-яa-z.?!\n]*+(?:\n[^а-яa-z.?!\n]*+)?
       (?=(?-i:[а-яa-z]))|
    (?<=\b[а-юa-z])\.|
    \n[^а-яa-z.?!\n]*+(?=(?-i:[а-яa-z]))|
    \d++(?:\.\d++)?|
    (?:"(?=[^\s.]).*?(?<=[^\s])"|")|
    (?:\((?=[^\s.]).*?(?<=[^\s])\)|\( )
)+
[?!\n.]*
}isx'; 

$i=0; 
$s=false;
while (preg_match($re, $text, $m, PREG_OFFSET_CAPTURE, $i)) {
   if($s) {
      $predl[count($predl)-1].=$m[0][0];
   } else {
      $predl[]=$m[0][0];
   }
   $i=$m[0][1]+strlen($m[0][0]);
   if (preg_match('/(?<=[^.]\.)\G(?!\.)/', $text, $w, 0, $i) && in_array($m[1][0], $sokr))  {
	   $s=true;
   } else {
       $s=false;
   }  
}
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху