在PHP中从字符串中检测语言

35

在PHP中,是否有一种方法可以检测字符串的语言?假设该字符串是以UTF-8格式编码的。


2
你想测试一个字符串是否包含非英文字符?你能定义一下“英文”是什么吗? - strager
4
法国人的问题在于他们没有“企业家”这个词。 - Pete Kirkham
1
基本上我想做的是,我有一个包含用户评论的数组,每个评论可能是不同的语言。在PHP后端,如果评论不是英语(比如法语或日语),我想设置一个标志,前端将显示一个翻译按钮,如果标志被设置。 - Beier
你想要做的完全可以用 JavaScript 和 Google 实现。你只需要做一个包含(include)就行了,不需要做任何其他事情。 - Esteban Küber
你可能想尝试谷歌的cld2! - Steel Brain
19个回答

36

我已经使用了Text_LanguageDetect pear包,结果还可以。它非常简单易用,并且有一个包含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
)

你能解释一下我如何在共享主机上安装那个包吗?它给了我很多问题... 我认为这对我比谷歌的翻译API更有用;因为,谷歌限制了调用次数太多.... - Roozbeh15
@Roozbeh15:查看此链接以获取共享主机安装说明。 - Dennis
Text_LanguageDetect pear包对我来说产生了可怕的结果,“市中心豪华公寓”被检测为葡萄牙语... 我建议使用Google API的答案。 - Robert Sinclair

21

我知道这是一篇旧帖子,但在找不到任何可行解决方案后,我开发出了以下方案。

  • 其他建议对我的情况来说都太重且太繁琐了。
  • 我网站上支持有限数量的语言(目前是两种:'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');
      // French 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', 'mot');

      // 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');
      // 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 https://dev59.com/qHM_5IYBdhLWcg3wPAnU#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;
    }

我喜欢你的方法,认为它给出了一个很好的有根据的猜测。但是你的代码存在一些(小)问题,比如它不能计算句点(.)或逗号(,)之前的单词等。 - Nin
@Nin:是的,它将计算这些单词(.,将被替换为空格,因此成为“单词分隔符”)。但是,如果您的单词列表中包含非ASCII字符,则确实需要进行一些调整。 - Swiss Mister
对,你说得对。我没有注意到。我已经改用array_count_values(str_word_count($text,1))了。在我用它处理小字符串时,这似乎更快(微秒)。 - Nin
附加的法语和西班牙语单词:`$wordList['en'] = array ('the', 'be', 'to', 'of', 'and', 'a', 'in', 'that', 'have', 'I', 'it', 'for', 'not', 'on', 'with', 'he', 'as', 'you', 'do', 'at');` `$wordList['fr'] = array ('comme', 'que', 'était', 'pour', 'sur', 'sont', 'avec', 'être', 'à', 'un', 'ce', 'par', 'mais', 'que', 'est', 'il', 'eu', 'la', 'de', 'et', 'dans');` - Szekelygobe
@Szekelygobe:请修改您的评论,我可以添加您的条目。复制和粘贴时似乎错过了“es”行...另外:请添加列表的来源。 - Swiss Mister
@SwissMister:评论有字符限制,所以我添加了一个新的答案来发表我的评论。 - Szekelygobe

17

无法从字符类型中检测语言。目前还没有绝对可靠的方法来实现这一点。

不管采用何种方法,你只是在做一个有根据的猜测。有一些数学相关的文章可供参考


14

您可以使用 Google的AJAX语言API (现已废弃)在客户端完成此操作。

使用AJAX语言API,您可以仅使用Javascript在网页内对文本块进行翻译和语言检测。此外,您还可以在Web页面上的任何文本字段或文本区域启用转写。例如,如果您要将转写为印地语,则此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;
  }
});

7
原始版的Google语言API已经被废弃,而API2是需要付费的。另外,对于这样简单的用途,每100万个字符20美元似乎有点昂贵。 - Shawn Solomon
你可以获得300美元的免费信用额度,我在下面提供了一个PHP示例。 - Robert Sinclair

8

由于Google翻译API将停止提供免费服务,您可以尝试这个免费替代方案,它是Google翻译API的替代品:

http://detectlanguage.com


我喜欢它,但是看完他们的条款后,让我感到使用它们很紧张。 - Shawn Solomon

3

Text_LanguageDetect这个pear包的检测结果很糟糕:“luxury apartments downtown”被检测为葡萄牙语...

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"

您可以在此处获取您的Google翻译API密钥:https://console.cloud.google.com/apis/library/translate.googleapis.com/ 这是一个简单的示例,用于翻译短语。对于更复杂的应用程序,您需要限制您的API密钥并使用适当的库。

3

我试用了Text_LanguageDetect库,但是得到的结果并不是很好(比如,文本“test”被识别为爱沙尼亚语而非英语)。

我建议你尝试使用Yandex翻译API,该API可以免费使用1百万字符24小时,每月高达1千万个字符。根据文档,它支持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>";
?>

2
“test”不是一个合理的文本量。您应该至少有一句话,最好是两句或更多。 - jor

2

这需要更多的赞,非常好用!谢谢。 - Robert Sinclair
实际上我试了一下,它不太起作用... "市中心豪华公寓"被检测为葡萄牙语。 '豪华'和'市中心'都不是葡萄牙语单词.. 糟糕.. - Robert Sinclair
@RobertSinclair:你需要输入更多的文字来进行语言检测。通常,语言检测需要一个完整的句子。 - jor

2
我曾经使用https://github.com/patrickschur/language-detection,并在生产中使用,效果很好:
  • 它使用语言中的ngrams来检测最可能的语言(您的字符串/单词越多,准确性就越高),这似乎是一种可靠的成熟方法。
  • 支持110种语言,但您也可以限制只选择您感兴趣的语言。
  • Trainer和Language detector可以轻松改进/定制。它在每种语言中使用《世界人权宣言》作为检测语言的基础,但如果您知道自己遇到的句子类型,可以轻松扩展或替换每种语言中使用的文本,并快速获得更好的结果。训练此库以变得更好非常容易。
  • 我建议在Trainer中增加setMaxNgrams(我将其设置为9000),然后运行一次,然后在Language detector类中也使用该设置。更改ngrams号码有点不直观(我必须查看代码才能找出它的工作原理),这是一个缺点,默认值(310)总是太低了。更多的ngrams可以使猜测更好。
  • 因为这个库非常小,所以相对容易理解发生了什么以及如何调整它。

我的使用:我正在分析CRM系统的电子邮件,以了解电子邮件是用哪种语言编写的,因此将文本发送到第三方服务不是一个选项。即使《世界人权宣言》可能不是将电子邮件语言分类的最佳基础(因为电子邮件通常具有公式化部分,例如问候语,这些不是《人权宣言》的一部分),但如果其中至少有5个单词,则它可以在99%的情况下确定正确的语言。

更新:当使用language-detection库时,我成功将电子邮件中的语言识别率提高到了近乎100%,方法如下:

  • 将其他常见短语添加到(相关的)语言样本中,例如“问候”,“最好的祝福”,“真诚问候”。这些类型的表达方式不在《世界人权宣言》中使用。通常使用的短语非常有助于语言识别,特别是人们经常使用的公式化短语(“你好”,“祝你有美好的一天”)。
  • 将最大ngram长度设置为4(而不是默认值3)。
  • 像以前一样保持maxNgrams为9000。

这些会使库变慢一些,因此如果可能的话,建议以异步方式使用它们并测量性能。在我的情况下,速度已经足够快,而且更加准确。


2
您可以使用Google翻译API来检测语言并在必要时进行翻译。请注意保留HTML标签。

4
因为他们取消了这个免费选项,所以这可能不再是一个选择。此外,翻译评论可能不是一个好主意,不仅因为"翻译失误"的影响,而且因为用户可能根本不会读英语。如果一个网站把你的评论翻译成你看不懂的语言,你会感到多么震惊? - Shawn Solomon
在GitHub上有一个免费的翻译包可用,它可以让你检测语言(截至v3.0)https://github.com/Stichoza/google-translate-php - Stichoza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接