Разделете текст на отделни думи

Бих искал да разделя текст на отделни думи с помощта на PHP. Имате ли идея как да постигнете това?

Моят подход:

function tokenizer($text) {
    $text = trim(strtolower($text));
    $punctuation = '/[^a-z0-9äöüß-]/';
    $result = preg_split($punctuation, $text, -1, PREG_SPLIT_NO_EMPTY);
    for ($i = 0; $i < count($result); $i++) {
        $result[$i] = trim($result[$i]);
    }
    return $result; // contains the single words
}
$text = 'This is an example text, it contains commas and full-stops. Exclamation marks, too! Question marks? All punctuation marks you know.';
print_r(tokenizer($text));

Това добър подход ли е? Имате ли идея за подобрение?

Благодаря предварително!


person caw    schedule 26.04.2009    source източник


Отговори (6)


Използвайте класа \p{P}, който съответства на който и да е уникод пунктуационен знак, комбиниран с класа \s интервал.

$result = preg_split('/((^\p{P}+)|(\p{P}*\s+\p{P}*)|(\p{P}+$))/', $text, -1, PREG_SPLIT_NO_EMPTY);

Това ще се раздели на група от един или повече празни знаци, но също така ще засмуче всички околни препинателни знаци. Той също така съвпада с препинателни знаци в началото или края на низа. Това дискриминира случаи като „недей“ и „той каза „ау!““

person moinudin    schedule 26.04.2009
comment
+1, не съм сигурен, но как ще се справи това с äöüß. Регулярният израз обикновено класифицира ли äöüß като знаци на дума? - person Peter Perháč; 26.04.2009
comment
Благодаря ти. Това вероятно няма да работи за английски текстове, но също така искам да извлека немски умлаути (ä, ö, ü), ß и числа в низ. \W нямаше да извлече Fri3nd, нали? - person caw; 26.04.2009
comment
Изглежда не, но актуализиран отговор с нещо подобно, което работи. - person moinudin; 26.04.2009
comment
Актуализираният отговор работи с perl (на който се базира php regex): $ echo äöüß, test | perl -e 'while (‹›) { if (/([\p{P}\s]+)/) { print $1\n; } }', - person moinudin; 26.04.2009
comment
Не трябва ли да се разделя на don и t? - person Eugene Yokota; 26.04.2009
comment
Актуализира го, за да се справи с такъв случай :) - person moinudin; 26.04.2009
comment
Благодаря, marcog, работи перфектно! Но наистина ли е по-добър от моя актуализиран код по-горе? Всъщност каква е разликата между нашите подходи? Едното по-бързо ли е от другото? - person caw; 26.04.2009
comment
Във вашия подход вие указвате непунктуационните знаци. Следователно ще пропуснете някои случаи, напр. á. Защо да се опитвате да ги посочите ръчно, когато целият набор от уникод пунктуационни знаци вече е дефиниран? И както eed3si9n посочи с моя първоначален отговор, вашият ще разбие думи като не. - person moinudin; 26.04.2009
comment
@marcog Някаква идея какъв би бил еквивалентът на Javascript на това? Опитах да направя str.split(/((^\p{P}+)|(\p{P}*\s+\p{P}*)|(\p{P}+$))/);, но не работи. Моля помогнете.. - person supersan; 20.04.2018
comment
Какво да направя, ако искам да премахна всички номера? - person Jignesh Manek; 31.08.2018

Tokenize - strtok.

<?php
$text = 'This is an example text, it contains commas and full stops. Exclamation marks, too! Question marks? All punctuation marks you know.';
$delim = ' \n\t,.!?:;';

$tok = strtok($text, $delim);

while ($tok !== false) {
    echo "Word=$tok<br />";
    $tok = strtok($delim);
}
?>
person Eugene Yokota    schedule 26.04.2009
comment
Благодаря ви, мисля, че тази функция се справя добре. - person caw; 26.04.2009
comment
Това няма да работи, ако получите : или ; или всеки друг препинателен знак, който не сте отчетли. - person moinudin; 26.04.2009
comment
@marcog, добавих : и ;. {P} не улавя ли апостроф и тире? - person Eugene Yokota; 26.04.2009
comment
Какво ще кажете за случаи на такова цитиране? Моят актуализиран отговор прави разлика между тези случаи. - person moinudin; 26.04.2009
comment
Отлична идея. Добавено +1. Единственото нещо е, че трябва да има двойни кавички около $delim = \n\t,.!?:;; С единичните кавички не работи правилно, разделя се и на буквата n. - person Oleksiy Muzalyev; 02.12.2017

Първо бих направил низа с малки букви, преди да го разделя. Това би направило модификатора i и последващата обработка на масива ненужни. Освен това бих използвал \W стенограмата за знаци, които не са думи и бих добавил + множител.

$text = 'This is an example text, it contains commas and full stops. Exclamation marks, too! Question marks? All punctuation marks you know.';
$result = preg_split('/\W+/', strtolower($text), -1, PREG_SPLIT_NO_EMPTY);

Редактиране   Използвайте знака на Unicode свойства вместо \W както предлага marcog. Нещо като [\p{P}\p{Z}] (препинателни знаци и разделителни знаци) би покрило знаците по-конкретно от \W.

person Gumbo    schedule 26.04.2009
comment
Благодаря, идеята да изпълним strtolower() преди е много добра. Ще използвам това. - person caw; 26.04.2009
comment
Каква е целта на strtolower(), ако се разделяте с \W? Искате ли да добавите модификатор на шаблон u? Бележка за изследователите... \W няма да съответства на долна черта. - person mickmackusa; 13.09.2020

можете също да използвате функцията PHP strtok(), за да извлечете символи на низ от вашия голям низ. можете да го използвате така:

 $result = array();
 // your original string
 $text = 'This is an example text, it contains commas and full stops. Exclamation marks, too! Question marks? All punctuation marks you know.';
 // you pass strtok() your string, and a delimiter to specify how tokens are separated. words are seperated by a space.
 $word = strtok($text,' ');
 while ( $word !== false ) {
     $result[] = $word;
     $word = strtok(' ');
 }

вижте повече относно php документацията за strtok()

person farzad    schedule 26.04.2009
comment
каква е разликата между това и explode(' ', $text); - person roopunk; 24.06.2015
comment
Примерният код във въпроса е токенизатор, отговорът ми намекваше, че PHP има вграден токенизатор на низове. Също така explode() ще върне всички думи от текста наведнъж, но използвайки strtok() повикващият има избор да спре търсенето на думи в текста, веднага щом е изпълнено желаното условие. Освен тази, не се сещам за друга разлика. - person farzad; 25.06.2015

Do:

str_word_count($text, 1);

Или ако имате нужда от поддръжка на unicode:

function str_word_count_Helper($string, $format = 0, $search = null)
{
    $result = array();
    $matches = array();

    if (preg_match_all('~[\p{L}\p{Mn}\p{Pd}\'\x{2019}' . preg_quote($search, '~') . ']+~u', $string, $matches) > 0)
    {
        $result = $matches[0];
    }

    if ($format == 0)
    {
        return count($result);
    }

    return $result;
}
person Alix Axel    schedule 26.04.2009
comment
Благодаря, но това няма да работи. Fri3nd няма да бъде извлечен, но трябва. - person caw; 26.04.2009
comment
Не разбирам защо трябва да се извлича Fri3nd. Премахнато от масива, разбито на Fri3 и nd (или подобно)? о.о - person David says reinstate Monica; 26.04.2009
comment
Ако искате да разглеждате числата като думи, просто направете str_word_count_Helper($string, 1, '0123456789'); - person Alix Axel; 26.04.2009

Можете също да използвате метода explode : http://php.net/manual/en/function.explode.php

$words = explode(" ", $sentence);
person jfgrang    schedule 10.10.2012
comment
не работи с 2 или повече последователни интервала. трябва да използвате foreach с explode(" ", $sentence) в if($word == "") continue;, за да избегнете празни думи. - person LucScu; 06.04.2017