Оцените, если строка не на английском языке: лучшие и самые простые практики?

У меня достаточно длинная строка (5000+ символов), и мне нужно проверить, на английском ли она.

После короткого поиска в Интернете я нашел несколько решений:

  • использование PEAR Text_LanguageDetect (это выглядит привлекательно, но я все еще избегаю решений, которые я не понимаю, как они работают)
  • проверять частота букв (Я сделал функцию ниже с некоторыми комментариями)
  • проверьте строку для национальных символов (например, č, ß и т. д.)
  • проверьте строку на наличие маркеров, таких как «is», «the» или что-нибудь

Итак, функция следующая:

function is_english($str){
// Most used English chars frequencies
$chars = array(
array('e',12.702),
array('t', 9.056),
array('a', 8.167),
array('o', 7.507),
array('i', 6.966),
array('n', 6.749),
array('s', 6.327),
array('h', 6.094),
array('r', 5.987),
);

$str = strtolower($str);
$sum = 0;
foreach($chars as $key=>$char){
$i = substr_count($str,$char[0]);
$i = 100*$i/strlen($str);    // Normalization
$i = $i/$char[1];
$sum += $i;
}
$avg = $sum/count($chars);

// Calculation of mean square value
$value = 0;
foreach($chars as $char)
$value += pow($char[2]-$avg,2);

// Average value
$value = $value / count($chars);
return $value;
}

Обычно эта функция оценивает частоту символов и сравнивает ее с заданным шаблоном. Результат должен быть ближе к 0, так как частота ближе к шаблону.

К сожалению, это работает не так хорошо: в основном я могу считать, что результаты 0,05 и ниже — это английский, а выше — нет. Но там много английских строк имеют высокие значения, а многие иностранные (в моем случае в основном немецкие) — низкие.

Я не могу реализовать В третьих Решение пока я не смог найти комплексный набор символов — маркеры иностранных языков.

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

Какие-нибудь мысли?

PS После некоторого обсуждения Зод предложил, чтобы этот вопрос дублировал вопрос Регулярное выражение для соответствия не английским символам?, который отвечает только частично. Поэтому я хотел бы сохранить этот вопрос независимым.

3

Решение

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

Вы можете найти несколько полных списков по адресу: https://en.wikipedia.org/wiki/Most_common_words_in_English

В вашей текущей реализации вы столкнетесь с некоторыми неудачами, потому что многие языки используют стандартный латинский алфавит. Даже языки, которые выходят за рамки стандартного латинского алфавита, обычно используют, так сказать, «английские символы». Например, предложение «Ich bin lustig» по-немецки, но использует только латинские буквенные символы. Аналогично, «Jeg er glad» — датский, но использует только латинские буквенные символы. Конечно, в строке из 5000+ символов вы, вероятно, увидите некоторые нелатинские символы, но это не гарантируется. Кроме того, но, сосредоточившись исключительно на частоте символов, вы можете обнаружить, что иностранные языки, использующие латинский алфавит, обычно имеют сходные частоты появления символов, что делает ваше существующее решение неэффективным.

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

Следующее является потенциальным решением:

<?php
$testString = "Some long string of text that you would like to test.";

// Words from: https://en.wikipedia.org/wiki/Most_common_words_in_English
$common_english_words = array('time', 'person', 'year', 'way', 'day', 'thing', 'man', 'world', 'life', 'hand', 'part', 'child', 'eye', 'woman', 'place', 'work', 'week', 'case', 'point', 'government', 'company', 'number', 'group', 'problem', 'fact', 'be', 'have', 'do', 'say', 'get', 'make', 'go', 'know', 'take', 'see', 'come', 'think', 'look', 'want', 'give', 'use', 'find', 'tell', 'ask', 'seem', 'feel', 'try', 'leave', 'call', 'good', 'new', 'first', 'last', 'long', 'great', 'little', 'own', 'other', 'old', 'right', 'big', 'high', 'different', 'small', 'large', 'next', 'early', 'young', 'important', 'few', 'public', 'bad', 'same', 'able', 'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from', 'up', 'about', 'into', 'over', 'after', 'beneath', 'under', 'above', 'the', 'and', 'a', 'that', 'i', 'it', 'not', 'he', 'as', 'you', 'this', 'but', 'his', 'they', 'her', 'she', 'or', 'an', 'will', 'my', 'one', 'all', 'would', 'there', 'their', 'I', 'we', 'what', 'so', 'out', 'if', 'who', 'which', 'me', 'when', 'can', 'like', 'no', 'just', 'him', 'people', 'your', 'some', 'could', 'them', 'than', 'then', 'now', 'only', 'its', 'also', 'back', 'two', 'how', 'our', 'well', 'even', 'because', 'any', 'these', 'most', 'us');

/* you might also consider replacing "'s" with ' ', because 's is common in English
as a contraction and simply removing the single quote could throw off the frequency. */
$transformedTest = preg_replace('@\s+@', ' ', preg_replace("@[^a-zA-Z'\s]@", ' ', strtolower($testString)));

$splitTest = explode(' ', $transformedTest);

$matchCount = 0;
for($i=0;$i<count($splitTest);$i++){
if(in_array($splitTest[$i], $common_english_words))
$matchCount++;
}

echo "raw count: $matchCount\n<br>\nPercent: " . ($matchCount/count($common_english_words))*100 . "%\n<br>\n";
if(($matchCount/count($common_english_words)) > 0.5){
echo "More than half of the test string is English. Text is likely English.";
}else{
echo "Text is likely a foreign language.";
}
?>

Здесь вы можете увидеть пример, который включает в себя две строки для тестирования (одна на немецком языке, а другая на английском): https://ideone.com/lfYcs2

В коде IDEOne при запуске его на английской строке вы увидите, что результат примерно на 69,3% соответствует обычным английским словам. При запуске на немецком языке процент совпадения составляет всего 4,57%, что соответствует общеупотребительным английским словам.

2

Другие решения

Эта проблема называется определение языка и нетривиально решить с помощью одной функции. Я предлагаю вам использовать LanguageDetector из Github.

1

я бы пошел с четвертым решением и попытался бы также искать не английский. Например, если вы найдете «the», то высокая вероятность для английского языка. Если вы найдете «эль» или «ля», то для испанского очень высока вероятность. Я бы искал «der», «die» и «das», тогда вполне возможно, что это немецкий.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector