Я пытаюсь разделить текст на слова:
$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, ....
Но у меня нет идеи, как избежать подобных случаев!
Кто-нибудь знает, как решить эту проблему?
Танк, Гранит
Или используйте regex 🙂
<?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" }
Взгляните на strtok . Он позволяет динамически изменять токены синтаксического разбора, поэтому вы можете разбить строку вручную в цикле while, нажав каждое разделенное слово в массив.
Моя первая идея была 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..
Используйте ". ",
Вместо ".",
В $delimiterList
.