Разбить текст на слова проблема PHP, сложная задача - PullRequest
2 голосов
/ 21 октября 2009

Я пытаюсь разбить текст на слова:

$delimiterList = array(" ", ".", "-", ",", ";", "_", ":",
           "!", "?", "/", "(", ")", "[", "]", "{", "}", "<", ">", "\r", "\n",
           '"');
$words = mb_split($delimiterList, $string);

, который отлично работает со строками, но я застреваю в некоторых случаях, когда мне приходится иметь дело с числами.

например. Если у меня есть текст «Посмотрите на это. Мой счет 3,14, и я рад этому». Теперь массив

[0]=>Look,
[1]=>at,
[2]=>this,
[3]=>My,
[4]=>score,
[5]=>is,
[6]=>3,
[7]=>14,
[8]=>and, ....

Тогда также 3.14 делится на 3 и 14, что не должно происходить в моем случае. Я имею в виду, точка должна делить две строки, а не два числа. Это должно быть как:

[0]=>Look,
[1]=>at,
[2]=>this,
[3]=>My,
[4]=>score,
[5]=>is,
[6]=>3.14,
[7]=>and, ....

Но я понятия не имею, как этого избежать!

Кто-нибудь есть идеи, как решить эту проблему?

Thanx, Granit

Ответы [ 4 ]

9 голосов
/ 21 октября 2009

Или используйте регулярное выражение:)

<?php
$str = "Look at this.My score is 3.14, and I am happy about it.";

// alternative to handle Marko's example (updated)
// /([\s_;?!\/\(\)\[\]{}<>\r\n"]|\.$|(?<=\D)[:,.\-]|[:,.\-](?=\D))/

var_dump(preg_split('/([\s\-_,:;?!\/\(\)\[\]{}<>\r\n"]|(?<!\d)\.(?!\d))/',
                    $str, null, PREG_SPLIT_NO_EMPTY));

array(13) {
  [0]=>
  string(4) "Look"
  [1]=>
  string(2) "at"
  [2]=>
  string(4) "this"
  [3]=>
  string(2) "My"
  [4]=>
  string(5) "score"
  [5]=>
  string(2) "is"
  [6]=>
  string(4) "3.14"
  [7]=>
  string(3) "and"
  [8]=>
  string(1) "I"
  [9]=>
  string(2) "am"
  [10]=>
  string(5) "happy"
  [11]=>
  string(5) "about"
  [12]=>
  string(2) "it"
}
6 голосов
/ 21 октября 2009

Взгляните на strtok . Он позволяет динамически изменять токены синтаксического анализа, поэтому вы можете вручную разбить строку на части в цикле while, помещая каждое разделенное слово в массив.

1 голос
/ 21 октября 2009

Моей первой идеей было preg_match_all('/\w+/', $string, $matches);, но это дает результат, аналогичный тому, который вы получили. Проблема в том, что числа, разделенные точкой, очень неоднозначны. Это может означать как десятичную точку, так и конец предложения, поэтому нам нужен способ изменить строку таким образом, чтобы исключить двойное значение.

Например, в этом предложении у нас есть несколько частей, которые мы хотели бы сохранить как одно слово: "Look at this.My score is 3.14, and I am happy about it. It's not 334,3 and today's not 2009-12-12 11:12:13.".

Мы начнем с создания словаря search-> replace для кодирования исключений во что-то, что не будет разделено:

$encode = array(
    '/(\d+?)\.(\d+?)/' => '\\1DOT\\2',
    '/(\d+?),(\d+?)/' => '\\1COMMA\\2',
    '/(\d+?)-(\d+?)-(\d+?) (\d+?):(\d+?):(\d+?)/' => '\\1DASH\\2DASH\\3SPACE\\4COLON\\5COLON\\6'
);

Далее мы кодируем исключения:

foreach ($encode as $regex => $repl) {
    $string = preg_replace($regex, $repl, $string);
}

Разделить строку:

preg_match_all('/\w+/', $string, $matches);

И преобразовать закодированное слово обратно:

$decode = array(
    'search' =>  array('DOT', 'COMMA', 'DASH', 'SPACE', 'COLON'),
    'replace' => array('.',   ',',     '-',    ' ',     ':'    )
);
foreach ($matches as $k => $v) {
    $matches[$k] = str_replace($decode['search'], $decode['replace'], $v);
}

$matches теперь содержит оригинальное предложение, разбитое на слова с правильными исключениями.

Вы можете сделать регулярное выражение, используемое в исключениях, таким простым или сложным, как вам нравится, но некоторая двусмысленность всегда будет проходить, например, два отправления с первым, заканчивающимся, а следующий, начинающийся с числа: Number of the counting shall be 3.3 only and nothing but the 3.5 is right out..

0 голосов
/ 21 октября 2009

Используйте ". ", вместо ".", в $delimiterList.

...