Определить язык из строки в PHP

В PHP есть ли способ определения языка строки? Предположим, что строка в формате UTF-8.

20 ответов

Решение

Вы не можете определить язык по типу символа. И нет надежных способов сделать это.

С любым методом вы просто делаете обоснованное предположение. Есть несколько статей по математике

Я использовал пакет груши Text_LanguageDetect с некоторыми разумными результатами. Он очень прост в использовании и имеет скромную 52-языковую базу данных. Недостатком является отсутствие обнаружения восточноазиатских языков.

require_once 'Text/LanguageDetect.php';
$l = new Text_LanguageDetect();
$result = $l->detect($text, 4);
if (PEAR::isError($result)) {
    echo $result->getMessage();
} else {
    print_r($result);
}

результаты в:

Array
(
    [german] => 0.407037037037
    [dutch] => 0.288065843621
    [english] => 0.283333333333
    [danish] => 0.234526748971
)

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

  • другие предложения слишком тяжелы и слишком громоздки для моей ситуации
  • Я поддерживаю конечное число языков на моем веб-сайте (на данный момент два: "en" и "de" - но решение обобщено для большего).
  • Мне нужно правдоподобное предположение о языке сгенерированной пользователем строки, и у меня есть запасной вариант (языковая настройка пользователя).
  • Поэтому я хочу найти решение с минимальным количеством ложных срабатываний, но меня не волнует ложное отрицание.

Решение использует 20 самых распространенных слов в языке, подсчитывает вхождения в стоге сена. Затем он просто сравнивает количество первых и вторых наиболее просчитанных языков. Если номер занявший второе место составляет менее 10% от победителя, победитель получает все.

Кодекс - любые предложения по улучшению скорости приветствуются!

    function getTextLanguage($text, $default) {
      $supported_languages = array(
          'en',
          'de',
      );
      // German word list
      // from http://wortschatz.uni-leipzig.de/Papers/top100de.txt
      $wordList['de'] = array ('der', 'die', 'und', 'in', 'den', 'von', 
          'zu', 'das', 'mit', 'sich', 'des', 'auf', 'für', 'ist', 'im', 
          'dem', 'nicht', 'ein', 'Die', 'eine');
      // English word list
      // from http://en.wikipedia.org/wiki/Most_common_words_in_English
      $wordList['en'] = array ('the', 'be', 'to', 'of', 'and', 'a', 'in', 
          'that', 'have', 'I', 'it', 'for', 'not', 'on', 'with', 'he', 
          'as', 'you', 'do', 'at');
      // clean out the input string - note we don't have any non-ASCII 
      // characters in the word lists... change this if it is not the 
      // case in your language wordlists!
      $text = preg_replace("/[^A-Za-z]/", ' ', $text);
      // count the occurrences of the most frequent words
      foreach ($supported_languages as $language) {
        $counter[$language]=0;
      }
      for ($i = 0; $i < 20; $i++) {
        foreach ($supported_languages as $language) {
          $counter[$language] = $counter[$language] + 
            // I believe this is way faster than fancy RegEx solutions
            substr_count($text, ' ' .$wordList[$language][$i] . ' ');;
        }
      }
      // get max counter value
      // from http://stackru.com/a/1461363
      $max = max($counter);
      $maxs = array_keys($counter, $max);
      // if there are two winners - fall back to default!
      if (count($maxs) == 1) {
        $winner = $maxs[0];
        $second = 0;
        // get runner-up (second place)
        foreach ($supported_languages as $language) {
          if ($language <> $winner) {
            if ($counter[$language]>$second) {
              $second = $counter[$language];
            }
          }
        }
        // apply arbitrary threshold of 10%
        if (($second / $max) < 0.1) {
          return $winner;
        } 
      }
      return $default;
    }

Вы можете сделать это полностью на стороне клиента с помощью Google AJAX Language API (ныне несуществующего).

С помощью AJAX Language API вы можете переводить и определять язык блоков текста на веб-странице, используя только Javascript. Кроме того, вы можете включить транслитерацию в любом текстовом поле или текстовой области на своей веб-странице. Например, если вы транслитерировали на хинди, этот API позволит пользователям фонетически произносить слова на хинди с использованием английского языка и отображать их в скрипте хинди.

Вы можете автоматически определить язык строки

var text = "¿Dónde está el baño?";
google.language.detect(text, function(result) {
  if (!result.error) {
    var language = 'unknown';
    for (l in google.language.Languages) {
      if (google.language.Languages[l] == result.language) {
        language = l;
        break;
      }
    }
    var container = document.getElementById("detection");
    container.innerHTML = text + " is: " + language + "";
  }
});

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

google.language.translate("Hello world", "en", "es", function(result) {
  if (!result.error) {
    var container = document.getElementById("translation");
    container.innerHTML = result.translation;
  }
});

Поскольку Google Translate API закрывается как бесплатный сервис, вы можете попробовать эту бесплатную альтернативу, которая заменяет Google Translate API:

http://detectlanguage.com/

Я попробовал библиотеку Text_LanguageDetect, и результаты, которые я получил, были не очень хорошими (например, текст "test" был идентифицирован как эстонский, а не английский).

Я могу порекомендовать вам воспользоваться API-интерфейсом Яндекс-перевода, который БЕСПЛАТНО для 1 миллиона символов в течение 24 часов и до 10 миллионов символов в месяц. Поддерживает (согласно документации) более 60 языков.

<?php
function identifyLanguage($text)
{
    $baseUrl = "https://translate.yandex.net/api/v1.5/tr.json/detect?key=YOUR_API_KEY";
    $url = $baseUrl . "&text=" . urlencode($text);

    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_CAINFO, YOUR_CERT_PEM_FILE_LOCATION);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

    $output = curl_exec($ch);
    if ($output)
    {
        $outputJson = json_decode($output);
        if ($outputJson->code == 200)
        {
            if (strlen($outputJson->lang) > 0)
            {
                return $outputJson->lang;
            }
        }
    }

    return "unknown";
}

function translateText($text, $targetLang)
{
    $baseUrl = "https://translate.yandex.net/api/v1.5/tr.json/translate?key=YOUR_API_KEY";
    $url = $baseUrl . "&text=" . urlencode($text) . "&lang=" . urlencode($targetLang);

    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_CAINFO, YOUR_CERT_PEM_FILE_LOCATION);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);

    $output = curl_exec($ch);
    if ($output)
    {
        $outputJson = json_decode($output);
        if ($outputJson->code == 200)
        {
            if (count($outputJson->text) > 0 && strlen($outputJson->text[0]) > 0)
            {
                return $outputJson->text[0];
            }
        }
    }

    return $text;
}

header("content-type: text/html; charset=UTF-8");

echo identifyLanguage("エクスペリエンス");
echo "<br>";
echo translateText("エクスペリエンス", "en");
echo "<br>";
echo translateText("エクスペリエンス", "es");
echo "<br>";
echo translateText("エクスペリエンス", "zh");
echo "<br>";
echo translateText("エクスペリエンス", "he");
echo "<br>";
echo translateText("エクスペリエンス", "ja");
echo "<br>";
?>

Пакет Text_LanguageDetect груши дал ужасные результаты: "роскошные апартаменты в центре города" были определены как португальский...

Google API по-прежнему является лучшим решением, они дают 300$ бесплатного кредита и предупреждают, прежде чем взимать с вас плату

Ниже приведена очень простая функция, которая использует file_get_contents для загрузки языка, обнаруженного API, поэтому нет необходимости загружать или устанавливать библиотеки и т. Д.

function guess_lang($str) {

    $str = str_replace(" ", "%20", $str);

    $content = file_get_contents("https://translation.googleapis.com/language/translate/v2/detect?key=YOUR_API_KEY&q=".$str);

    $lang = (json_decode($content, true));

    if(isset($lang))
        return $lang["data"]["detections"][0][0]["language"];
 }

Выполнение:

echo guess_lang("luxury apartments downtown montreal"); // returns "en"

Вы можете получить ключ API Google Translate здесь: https://console.cloud.google.com/apis/library/translate.googleapis.com/

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

Вы можете использовать API сервиса Lnag ID http://langid.net/identify-language-from-api.html

Вероятно, вы можете использовать Google Translate API для определения языка и перевода его при необходимости.

Вы можете узнать, как определить язык для строки в php с помощью пакета Text_LanguageDetect Pear или загрузить его, чтобы использовать его отдельно, как обычную библиотеку php.

У меня были хорошие результаты с https://github.com/patrickschur/language-detection и я использую его в производстве:

  • Он использует нграммы в языках для определения наиболее вероятного языка (чем длиннее ваша строка / чем больше слов, тем точнее он будет), что кажется надежным проверенным методом.
  • Поддерживается 110 языков, но вы также можете ограничить количество языков только теми, кто вас интересует.
  • Обучающий и языковой детектор может быть легко улучшен / настроен. Он использует Всеобщую декларацию прав человека на каждом из языков в качестве основы для определения языка, но если вы знаете, с какими типами предложений вы сталкиваетесь, вы можете легко расширить или заменить используемые тексты на каждом языке и быстро получить лучшие результаты. "Тренировать" эту библиотеку, чтобы стать лучше, легко.
  • Я бы предложил увеличить setMaxNgrams (я установил его на 9000) в Trainer и запустить его один раз, а затем также использовать эту настройку в классе детектора языка. Изменение числа ngrams немного неинтуитивно (мне пришлось просмотреть код, чтобы выяснить, как он работает), что является недостатком, и по умолчанию (310), на мой взгляд, всегда слишком мало. Больше нграмм делает гадание намного лучше.
  • Поскольку библиотека очень мала, было относительно легко понять, что происходит и как ее настроить.

Мое использование: я анализирую электронные письма для системы CRM, чтобы узнать, на каком языке написано электронное письмо, поэтому отправка текста в стороннюю службу была невозможной. Несмотря на то, что Всеобщая декларация прав человека, вероятно, не является наилучшей основой для классификации языка электронных писем (поскольку электронные письма часто имеют формальные части, такие как приветствия, которые не являются частью Декларации прав человека), она определяет правильный язык примерно в 99% случаев. случаи, если в нем хотя бы 5 слов.

Обновление: мне удалось улучшить распознавание языка в электронных письмах до 100% при использовании библиотеки определения языка следующими методами:

  • Добавьте дополнительные общие фразы к (соответствующим) языковым образцам, таким как "Привет", "С наилучшими пожеланиями", "С уважением". Подобные выражения не используются во Всеобщей декларации прав человека. Часто используемые фразы помогают распознавать язык, особенно формульные, которые часто используют мои люди ("Привет", "Хорошего дня"), если вы анализируете человеческое общение.
  • Установите максимальную длину ngram на 4 (вместо значения по умолчанию 3).
  • Держите maxNgrams на 9000, как и раньше.

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

Отвечаю для конкретного случая. Вот что я написал, чтобы узнать, написана ли строка на определенном языке, но с одним условием - разные языки имеют разные алфавиты. В моем случае слово (а) может быть на 3 языках - английском, болгарском и греческом (каждый с разным алфавитом). И мне нужно узнать, есть ли текст на болгарском, чтобы потом перевести его на греческий.

      class Language {
        protected $bgSymbols = array(
            'а', 'б', 'в', 'г', 'д', 'е', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ъ', 'ь', 'ч', 'щ', 'ш', 'ю', 'я',
            'А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ъ', 'Ь', 'Ч', 'Щ', 'Ш', 'Ю', 'Я'
        );
        
        public function checkIfForTranslate($string) {
            $result = false;
            $stringArray = array();
            preg_match_all('/./u', $string, $matches);
            if(isset($matches[0])) {
                $stringArray = $matches[0];
            }
            foreach($this->bgSymbols as $symbol) {
                $found = array_search($symbol, $stringArray);
                if($found !== false) {
                    $result = true;
                    break;
                }
            }
            return $result;
        }
    }

Надеюсь, это поможет кому-то с аналогичным случаем с моим.

Я брал документы на разных языках и сравнивал их с Unicode. Затем вы можете использовать некоторые байесовские рассуждения, чтобы определить, какой это язык, используя только символы Юникода. Это отделило бы французский от английского или русского.

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

Возможно, отправьте строку в этот язык guesser:

http://www.xrce.xerox.com/competencies/content-analysis/tools/guesser

Я использовал этот метод для проверки неанглийских, испанских и французских символов, используя строго PHP без каких-либо дополнительных языковых API или классов, начиная с PHP 5.1. Список языковых скриптов взят из: https://www.php.net/manual/en/regexp.reference.unicode.php См. Ниже

Улучшение состояло бы в том, чтобы добавить в PHP функцию, которая перечисляет все поддерживаемые языки сценариев, чтобы вам не приходилось заполнять массив вручную.

Сценарий использования был для блокировки нелатинских сообщений в форме, чтобы улучшить ее блокировку спама, поскольку форма получала много сообщений спама на русском, китайском и арабском языках. С тех пор, как это было реализовано, его количество снизилось с 40000 в неделю до менее 5, причем за последние 3 недели не было ни одного. Google Re-Captcha использовался, но его легко победить. #доволен

      <?php
$non_latin_text = "This is NOT english, spanish, or french (which are latin languages) because it has this char in it:  и";
$latin_text = "1234567890-=\][poiuytrewqasdfghjkl;'/.,mnbvcxz!@#$%^&*()_+|}{:\"?><QWERTYUIOPLKJHGFDSAZXCVBNM";

print_r(is_non_latin($non_latin_text)); //Returns TRUE
print_r(is_non_latin($latin_text)); //Returns FALSE
function is_non_latin($text)
{
   $text_script_languages = get_language_scripts($text);

   //All Latin characters and numbers which are Common and Latin.
   if (count($text_script_languages) == 2 && in_array('Common', $text_script_languages) && in_array('Latin', $text_script_languages))
   {
      return FALSE;
   }

   if (count($text_script_languages) == 1 && (in_array('Common', $text_script_languages) || in_array('Latin', $text_script_languages)))
   {
      return FALSE;
   }

   //If we are here, then the text had other language scripts in it.
   return TRUE;
}

function get_language_scripts($text)
{
   $scripts = array('Arabic', 'Armenian', 'Avestan', 'Balinese', 'Bamum', 'Batak', 'Bengali', 'Bopomofo', 'Brahmi', 'Braille', 'Buginese', 'Buhid', 'Canadian_Aboriginal', 'Carian', 'Chakma', 'Cham', 'Cherokee', 'Common', 'Coptic', 'Cuneiform', 'Cypriot', 'Cyrillic', 'Deseret', 'Devanagari', 'Egyptian_Hieroglyphs', 'Ethiopic', 'Georgian', 'Glagolitic', 'Gothic', 'Greek', 'Gujarati', 'Gurmukhi', 'Han', 'Hangul', 'Hanunoo', 'Hebrew', 'Hiragana', 'Imperial_Aramaic', 'Inherited', 'Inscriptional_Pahlavi', 'Inscriptional_Parthian', 'Javanese', 'Kaithi', 'Kannada', 'Katakana', 'Kayah_Li', 'Kharoshthi', 'Khmer', 'Lao', 'Latin', 'Lepcha', 'Limbu', 'Linear_B', 'Lisu', 'Lycian', 'Lydian', 'Malayalam', 'Mandaic', 'Meetei_Mayek', 'Meroitic_Cursive', 'Meroitic_Hieroglyphs', 'Miao', 'Mongolian', 'Myanmar', 'New_Tai_Lue', 'Nko', 'Ogham', 'Old_Italic', 'Old_Persian', 'Old_South_Arabian', 'Old_Turkic', 'Ol_Chiki', 'Oriya', 'Osmanya', 'Phags_Pa', 'Phoenician', 'Rejang', 'Runic', 'Samaritan', 'Saurashtra', 'Sharada', 'Shavian', 'Sinhala', 'Sora_Sompeng', 'Sundanese', 'Syloti_Nagri', 'Syriac', 'Tagalog', 'Tagbanwa', 'Tai_Le', 'Tai_Tham', 'Tai_Viet', 'Takri', 'Tamil', 'Telugu', 'Thaana', 'Thai', 'Tibetan', 'Tifinagh', 'Ugaritic', 'Vai', 'Yi');
 
   $found_scripts = array();

   foreach ($scripts AS $key => $script)
   {
      if (!empty($script))
      {
         if (preg_match( '/[\p{'.$script.'}]/u', $text))
         {
            $found_scripts[] = $script;
         }
      }
   }

   return $found_scripts;
}

Попробуй использовать ascii encode. я использую этот код для определения языков в моем проекте социального бота

function language($string) {
        $ru = array("208","209","208176","208177","208178","208179","208180","208181","209145","208182","208183","208184","208185","208186","208187","208188","208189","208190","208191","209128","209129","209130","209131","209132","209133","209134","209135","209136","209137","209138","209139","209140","209141","209142","209143");
        $en = array("97","98","99","100","101","102","103","104","105","106","107","108","109","110","111","112","113","114","115","116","117","118","119","120","121","122");
        $htmlcharacters = array("<", ">", "&amp;", "&lt;", "&gt;", "&");
        $string = str_replace($htmlcharacters, "", $string);
        //Strip out the slashes
        $string = stripslashes($string);
        $badthings = array("=", "#", "~", "!", "?", ".", ",", "<", ">", "/", ";", ":", '"', "'", "[", "]", "{", "}", "@", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", "|", "`");
        $string = str_replace($badthings, "", $string);
        $string = mb_strtolower($string);
        $msgarray = explode(" ", $string);
        $words = count($msgarray);
        $letters = str_split($msgarray[0]);
        $letters = ToAscii($letters[0]);
        $brackets = array("[",",","]");
        $letters = str_replace($brackets,  "", $letters);
        if (in_array($letters, $ru)) {
            $result = 'Русский' ; //russian
        } elseif (in_array($letters, $en)) {
            $result = 'Английский'; //english
        } else {
            $result = 'ошибка' . $letters; //error
        }} return $result;  

Одним из подходов может быть разбиение входной строки на слова, а затем поиск этих слов в английском словаре, чтобы увидеть, сколько их присутствует. Этот подход имеет несколько ограничений:

  • собственные имена не могут быть хорошо обработаны
  • орфографические ошибки могут нарушить ваш поиск
  • такие сокращения, как "lol" или "b4" не обязательно будут в словаре

Дополнительные слова для французского и испанского к швейцарскому ответу господина:

    // Franch word list
    // from https://1000mostcommonwords.com/1000-most-common-french-words/
    $wordList['fr'] = array ('comme', 'que',  'était',  'pour',  'sur',  'sont',  'avec',
                             'être',  'à',  'un',  'ce',  'par',  'mais',  'que',  'est',
                             'il',  'eu',  'la', 'et', 'dans');

    // Spanish word list
    // from https://spanishforyourjob.com/commonwords/
    $wordList['es'] = array ('que', 'no', 'a', 'la', 'el', 'es', 'y',
                             'en', 'lo', 'un', 'por', 'qué', 'si', 'una',
                             'los', 'con', 'para', 'está', 'eso', 'las');

Следующий код не требует каких-либо API или огромных зависимостей. В этом коде мы удаляем все символы, теги html (если вы работаете с html), объекты html и пробелы.

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

      function is_english($string)
{
    // Removing html tags
    $string = strip_tags($string);

    // Removing html entities
    $string = preg_replace('/&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-fA-F]{1,6});/is', '', $string);
    
    // Removing symbols
    $string = preg_replace('/[-!$%^&*()_+|~=`{}\[\]:";\'<>?,.\/#’—-–]/si', '', $string);

    // Removing spaces
    $string = preg_replace('/\s+/si', '', $string);
    
    // Counting english characters
    preg_match_all('/\w+/si', $string, $english_match);
    $english_char = strlen(implode('', $english_match[0]));

    // Counting non english characters
    preg_match_all('/\W+/si', $string, $match);
    $non_english_char = strlen(implode('', $match[0]));

    // Checks if number of english characters are grater

    if ($english_char > $non_english_char)
    {
        return true;
    }

    return false;
}

Вы можете реализовать модуль Apache Tika с Java, вставить результаты в текстовый файл, в БД и т. Д., А затем прочитать из файла db, что угодно с помощью php. Если у вас нет такого большого количества контента, вы можете использовать API Google, хотя имейте в виду, что ваши звонки будут ограничены, и вы можете отправлять в API только ограниченное количество символов. На момент написания статьи я закончил тестирование API-версии 1 (которая оказалась не очень точной) и 2-й лабораторной версии (после того как я прочитал, что ограничение в 100 000 символов в день).

Другие вопросы по тегам