У меня есть массив PHP:
$excerpts = array(
'I love cheap red apples',
'Cheap red apples are what I love',
'Do you sell cheap red apples?',
'I want red apples',
'Give me my red apples',
'OK now where are my apples?'
);
Я хотел бы найти все n-граммы в этих строках, чтобы получить такой результат:
Я попытался взорвать массив и затем проанализировать его, но это глупо, потому что новые n-граммы могут быть найдены из-за конкатенации строк, которым нечего видеть между собой.
Как бы вы поступили?
Я хочу найти группу слов, не зная их, хотя
с вашей функцией мне нужно предоставить их, прежде чем что-либо
Попробуй это:
mb_internal_encoding('UTF-8');
$joinedExcerpts = implode(".\n", $excerpts);
$sentences = preg_split('/[^\s|\pL]/umi', $joinedExcerpts, -1, PREG_SPLIT_NO_EMPTY);
$wordsSequencesCount = array();
foreach($sentences as $sentence) {
$words = array_map('mb_strtolower',
preg_split('/[^\pL+]/umi', $sentence, -1, PREG_SPLIT_NO_EMPTY));
foreach($words as $index => $word) {
$wordsSequence = '';
foreach(array_slice($words, $index) as $nextWord) {
$wordsSequence .= $wordsSequence ? (' ' . $nextWord) : $nextWord;
if( !isset($wordsSequencesCount[$wordsSequence]) ) {
$wordsSequencesCount[$wordsSequence] = 0;
}
++$wordsSequencesCount[$wordsSequence];
}
}
}
$ngramsCount = array_filter($wordsSequencesCount,
function($count) { return $count > 1; });
Я предполагаю, что вы хотите только повторную группу слов.
Выход из var_dump($ngramsCount);
является:
array (size=11)
'i' => int 3
'i love' => int 2
'love' => int 2
'cheap' => int 3
'cheap red' => int 3
'cheap red apples' => int 3
'red' => int 5
'red apples' => int 5
'apples' => int 6
'are' => int 2
'my' => int 2
Код можно оптимизировать, чтобы, например, использовать меньше памяти.
Код предоставлен Педро Амарал Коуту выше очень хорошо.
Поскольку я использую его для французского, я изменил регулярное выражение следующим образом:
$sentences = preg_split('/[^\s|\pL-\'’]/umi', $joinedExcerpts, -1, PREG_SPLIT_NO_EMPTY);
Таким образом, мы можем проанализировать слова, содержащие дефисы и апострофы («est-ce que», «j’ai» и т. Д.)
Попробуйте это (используя implode
, так как это вы упомянули как попытку):
$ngrams = array(
'cheap red apples',
'red apples',
'apples',
);
$joinedExcerpts = implode("\n", $excerpts);
$nGramsCount = array_fill_keys($ngrams, 0);
var_dump($ngrams, $joinedExcerpts);
foreach($ngrams as $ngram) {
$regex = '/(?:^|[^\pL])(' . preg_quote($ngram, '/') . ')(?:$|[^\pL])/umi';
$nGramsCount[$ngram] = preg_match_all($regex, $joinedExcerpts);
}
Предполагая, что вы просто хотите посчитать количество вхождений строки:
$cheapRedAppleCount = 0;
$redAppleCount = 0;
$appleCount = 0;
for($i = 0; $i < count($excerpts); $i++)
{
$cheapRedAppleCount += preg_match_all('cheap red apples', $excerpts[$i]);
$redAppleCount += preg_match_all('red apples', $excerpts[$i]);
$appleCount += preg_match_all('apples', $excerpts[$i]);
}
preg_match_all
возвращает количество совпадений в данной строке, так что вы можете просто добавить количество совпадений на счетчик.
preg_match_all для дополнительной информации.
Извиняюсь, если я неправильно понял.