在 PHP 中,有没有办法检测字符串的语言?假设字符串是 UTF-8 格式。
18 回答
我使用了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
)
我知道这是一篇旧帖子,但这是我在没有找到任何可行的解决方案后开发的。
- 其他建议对我的情况来说太重太麻烦了
- 我在我的网站上支持有限数量的语言(目前有两种:'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');
// 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 http://stackoverflow.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 语言 API(现已失效)完全在客户端完成此操作。
使用 AJAX 语言 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 的替代品:
我尝试了 Text_LanguageDetect 库,但得到的结果不是很好(例如,文本“test”被识别为爱沙尼亚语而不是英语)。
我可以建议您尝试使用Yandex Translate API,它可以在 24 小时内免费使用 100 万个字符,每月最多可以使用 1000 万个字符。它支持(根据文档)超过 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梨包产生可怕的结果:“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 密钥并使用该库。
您可能可以使用Google Translate API来检测语言并在必要时进行翻译。
您可以了解如何使用Text_LanguageDetect Pear 包在 php 中检测字符串的语言,或者像常规 php 库一样下载单独使用它。
一种方法可能是将输入字符串分解为单词,然后在英语词典中查找这些单词以查看其中有多少。这种方法有一些限制:
- 专有名词可能处理不好
- 拼写错误可能会破坏您的查找
- 像“lol”或“b4”这样的缩写不一定会出现在字典中
也许将字符串提交给这个语言猜测器:
http://www.xrce.xerox.com/competencies/content-analysis/tools/guesser
我会从各种语言中获取文档,并根据 Unicode 引用它们。然后,您可以使用一些贝叶斯推理来仅通过使用的 unicode 字符来确定它是哪种语言。这会将法语与英语或俄语分开。
除了在语言词典中查找单词以确定语言(使用类似的概率方法)之外,我不确定还能做什么。
尝试使用 ascii 编码。我使用该代码来确定我的社交机器人项目中的 ru\en 语言
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("<", ">", "&", "<", ">", "&");
$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;
我在https://github.com/patrickschur/language-detection上取得了不错的成绩,并在生产中使用它:
- 它使用语言中的 ngrams 来检测最可能的语言(字符串越长/单词越多,它会越准确),这似乎是一种经过验证的可靠方法。
- 支持 110 种语言,但您也可以将语言数量限制为仅您感兴趣的语言。
- 培训师和语言检测器可以轻松改进/定制。它使用每种语言中的《世界人权宣言》作为检测语言的基础,但是如果您知道您遇到的句子类型,您可以轻松扩展或替换每种语言中使用的文本并快速获得更好的结果。“训练”这个库变得更好很容易。
- 我建议在 Trainer 中增加 setMaxNgrams(我将其设置为 9000)并运行一次,然后在语言检测器类中也使用该设置。更改 ngrams 编号有点不直观(我必须查看代码才能了解它是如何工作的),这是一个缺点,而且我认为默认值 (310) 总是太低。更多的 ngram 使猜测变得更好。
- 因为库非常小,所以很容易理解正在发生的事情以及如何调整它。
我的用法:我正在为 CRM 系统分析电子邮件,以了解电子邮件是用什么语言编写的,因此无法将文本发送到第三方服务。尽管《世界人权宣言》可能不是对电子邮件语言进行分类的最佳依据(因为电子邮件通常具有问候语等公式化部分,这不是《人权宣言》的一部分),但它在 99% 的语言中识别出正确的语言情况下,如果其中至少有 5 个单词。
更新:通过以下方法使用语言检测库时,我设法将电子邮件中的语言识别率提高到基本上 100%:
- 在(相关)语言示例中添加其他常用短语,例如“问候”、“最好的问候”、“真诚的”。《世界人权宣言》中没有使用这种表达方式。如果您正在分析人类交流,常用短语对语言识别有很大帮助,尤其是我的人类经常使用的公式化短语(“Hello”,“Have a nice day”)。
- 将最大 ngram 长度设置为 4(而不是默认的 3)。
- 像以前一样将 maxNgrams 保持在 9000。
这些确实使库有点慢,所以我建议尽可能以异步方式使用它们并测量性能。就我而言,它足够快而且更准确。
从 PHP 5.1 开始,我使用此方法严格使用 PHP 来检查非英语、西班牙语、法语字符,而无需任何额外的语言 API 或类。语言脚本列表来自: 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;
}
您可以使用 Java 实现 Apache Tika 模块,将结果插入 txt 文件、数据库等,然后从文件 db 中读取,无论使用 php。如果您没有那么多内容,您可以使用 Google 的 API,但请记住,您的调用将受到限制,并且您只能向 API 发送有限数量的字符。在撰写本文时,我已经完成了 API 的第 1 版(结果并不那么准确)和实验室第 2 版(在我读到每天有 100,000 个字符的上限后我放弃了)的测试。
瑞士先生回答的法语和西班牙语附加词:
// 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');
我的回答是针对特定情况的。这是我写的内容,以查找字符串是否为特定语言,但有一个条件 - 不同的语言有不同的字母表。在我的例子中,单词可以是 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;
}
}
希望这可以帮助与我有类似情况的人。