PHP 中的 Schinke 拉丁语词干算法
本网站提供“Schinke Latin Stemming Algorithm”下载,以便在Snowball 词干系统。
我想使用这个算法,但我不想使用 Snowball。
好处是:该页面上有一些伪代码,您可以将其转换为 PHP功能。这是我尝试过的:
<?php
function stemLatin($word) {
// output = array(NOUN-BASED STEM, VERB-BASED STEM)
// DEFINE CLASSES BEGIN
$queWords = array('atque', 'quoque', 'neque', 'itaque', 'absque', 'apsque', 'abusque', 'adaeque', 'adusque', 'denique', 'deque', 'susque', 'oblique', 'peraeque', 'plenisque', 'quandoque', 'quisque', 'quaeque', 'cuiusque', 'cuique', 'quemque', 'quamque', 'quaque', 'quique', 'quorumque', 'quarumque', 'quibusque', 'quosque', 'quasque', 'quotusquisque', 'quousque', 'ubique', 'undique', 'usque', 'uterque', 'utique', 'utroque', 'utribique', 'torque', 'coque', 'concoque', 'contorque', 'detorque', 'decoque', 'excoque', 'extorque', 'obtorque', 'optorque', 'retorque', 'recoque', 'attorque', 'incoque', 'intorque', 'praetorque');
$suffixesA = array('ibus, 'ius, 'ae, 'am, 'as, 'em', 'es', ia', 'is', 'nt', 'os', 'ud', 'um', 'us', 'a', 'e', 'i', 'o', 'u');
$suffixesB = array('iuntur', 'beris', 'erunt', 'untur', 'iunt', 'mini', 'ntur', 'stis', 'bor', 'ero', 'mur', 'mus', 'ris', 'sti', 'tis', 'tur', 'unt', 'bo', 'ns', 'nt', 'ri', 'm', 'r', 's', 't');
// DEFINE CLASSES END
$word = strtolower(trim($word)); // make string lowercase + remove white spaces before and behind
$word = str_replace('j', 'i', $word); // replace all <j> by <i>
$word = str_replace('v', 'u', $word); // replace all <v> by <u>
if (substr($word, -3) == 'que') { // if word ends with -que
if (in_array($word, $queWords)) { // if word is a queWord
return array($word, $word); // output queWord as both noun-based and verb-based stem
}
else {
$word = substr($word, 0, -3); // remove the -que
}
}
foreach ($suffixesA as $suffixA) { // remove suffixes for noun-based forms (list A)
if (substr($word, -strlen($suffixA)) == $suffixA) { // if the word ends with that suffix
$word = substr($word, 0, -strlen($suffixA)); // remove the suffix
break; // remove only one suffix
}
}
if (strlen($word) >= 2) { $nounBased = $word; } else { $nounBased = ''; } // add only if word contains two or more characters
foreach ($suffixesB as $suffixB) { // remove suffixes for verb-based forms (list B)
if (substr($word, -strlen($suffixA)) == $suffixA) { // if the word ends with that suffix
switch ($suffixB) {
case 'iuntur', 'erunt', 'untur', 'iunt', 'unt': $word = substr($word, 0, -strlen($suffixB)).'i'; break; // replace suffix by <i>
case 'beris', 'bor', 'bo': $word = substr($word, 0, -strlen($suffixB)).'bi'; break; // replace suffix by <bi>
case 'ero': $word = substr($word, 0, -strlen($suffixB)).'eri'; break; // replace suffix by <eri>
default: $word = substr($word, 0, -strlen($suffixB)); break; // remove the suffix
}
break; // remove only one suffix
}
}
if (strlen($word) >= 2) { $verbBased = $word; } else { $verbBased = ''; } // add only if word contains two or more characters
return array($nounBased, $verbBased);
}
?>
我的问题:
1)这段代码能正常工作吗?它遵循算法规则吗?
2)如何改进代码(性能)?
预先非常感谢您!
This website offers the "Schinke Latin stemming algorithm" for download to use it in the Snowball stemming system.
I want to use this algorithm, but I don't want to use Snowball.
The good thing: There's some pseudocode on that page which you could translate to a PHP function. This is what I've tried:
<?php
function stemLatin($word) {
// output = array(NOUN-BASED STEM, VERB-BASED STEM)
// DEFINE CLASSES BEGIN
$queWords = array('atque', 'quoque', 'neque', 'itaque', 'absque', 'apsque', 'abusque', 'adaeque', 'adusque', 'denique', 'deque', 'susque', 'oblique', 'peraeque', 'plenisque', 'quandoque', 'quisque', 'quaeque', 'cuiusque', 'cuique', 'quemque', 'quamque', 'quaque', 'quique', 'quorumque', 'quarumque', 'quibusque', 'quosque', 'quasque', 'quotusquisque', 'quousque', 'ubique', 'undique', 'usque', 'uterque', 'utique', 'utroque', 'utribique', 'torque', 'coque', 'concoque', 'contorque', 'detorque', 'decoque', 'excoque', 'extorque', 'obtorque', 'optorque', 'retorque', 'recoque', 'attorque', 'incoque', 'intorque', 'praetorque');
$suffixesA = array('ibus, 'ius, 'ae, 'am, 'as, 'em', 'es', ia', 'is', 'nt', 'os', 'ud', 'um', 'us', 'a', 'e', 'i', 'o', 'u');
$suffixesB = array('iuntur', 'beris', 'erunt', 'untur', 'iunt', 'mini', 'ntur', 'stis', 'bor', 'ero', 'mur', 'mus', 'ris', 'sti', 'tis', 'tur', 'unt', 'bo', 'ns', 'nt', 'ri', 'm', 'r', 's', 't');
// DEFINE CLASSES END
$word = strtolower(trim($word)); // make string lowercase + remove white spaces before and behind
$word = str_replace('j', 'i', $word); // replace all <j> by <i>
$word = str_replace('v', 'u', $word); // replace all <v> by <u>
if (substr($word, -3) == 'que') { // if word ends with -que
if (in_array($word, $queWords)) { // if word is a queWord
return array($word, $word); // output queWord as both noun-based and verb-based stem
}
else {
$word = substr($word, 0, -3); // remove the -que
}
}
foreach ($suffixesA as $suffixA) { // remove suffixes for noun-based forms (list A)
if (substr($word, -strlen($suffixA)) == $suffixA) { // if the word ends with that suffix
$word = substr($word, 0, -strlen($suffixA)); // remove the suffix
break; // remove only one suffix
}
}
if (strlen($word) >= 2) { $nounBased = $word; } else { $nounBased = ''; } // add only if word contains two or more characters
foreach ($suffixesB as $suffixB) { // remove suffixes for verb-based forms (list B)
if (substr($word, -strlen($suffixA)) == $suffixA) { // if the word ends with that suffix
switch ($suffixB) {
case 'iuntur', 'erunt', 'untur', 'iunt', 'unt': $word = substr($word, 0, -strlen($suffixB)).'i'; break; // replace suffix by <i>
case 'beris', 'bor', 'bo': $word = substr($word, 0, -strlen($suffixB)).'bi'; break; // replace suffix by <bi>
case 'ero': $word = substr($word, 0, -strlen($suffixB)).'eri'; break; // replace suffix by <eri>
default: $word = substr($word, 0, -strlen($suffixB)); break; // remove the suffix
}
break; // remove only one suffix
}
}
if (strlen($word) >= 2) { $verbBased = $word; } else { $verbBased = ''; } // add only if word contains two or more characters
return array($nounBased, $verbBased);
}
?>
My questions:
1) Will this code work correctly? Does it follow the algorithm's rules?
2) How could you improve the code (performance)?
Thank you very much in advance!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,你的函数将无法工作,它包含语法错误。例如,您有未闭合的引号,并且使用了错误的
switch
语法。这是我对该函数的重写。由于该页面上的伪算法并不精确,因此我必须进行一些解释。我以本文提到的示例起作用的方式对其进行了解释。
我也做了一些优化。第一个是我定义单词和后缀数组
static
。因此,对此函数的所有调用都共享相同的数组,这应该具有良好的性能;)此外,我还调整了数组,以便更有效地使用它们。我更改了
$queWords
数组,以便它可以用于快速哈希表查找,而不是缓慢的in_array
。此外,我已将后缀的长度保存在数组中。因此,您不需要在运行时计算它们(这真的非常慢)。我可能做了更多小的优化。我不知道这段代码快了多少,但应该快得多。此外,它现在适用于提供的示例。
这是代码:
No, your function will not work, it contains syntax errors. For example you have unclosed quotes and you use a wrong
switch
syntax.Here is my rewrite of the function. As the pseudoalgorithm on that page isn't really precise I had to do some interpreting. I interpreted it in a way that the examples mentioned in this article work.
I also did some optimizations. The first one is that I define the word and suffix arrays
static
. Thus all calls to this function share the same arrays which should be good fore performance ;)Furthermore I adjusted the arrays so they can be used more effective. I changed the
$queWords
array so it can be used for a fast hash-table lookup, not a slowin_array
. Furthermore I have saved the lengths for the suffixes in the array. Thus you don't need to compute them at runtime (which is really, really slow). I may have made more minor optimizations.I don't know how much faster this code is, but it should be much faster. Furthermore it now works on the examples provided.
Here is the code:
据我所知,这遵循您链接中描述的算法,并且应该可以正常工作。 (除了
$suffixesA
定义中的语法错误 - 您缺少几个撇号。)在性能方面,看起来这里没有太多收获,但是有我想到了一些事情。
如果在脚本的单次执行期间会多次调用此函数,则通过在函数外部定义这些数组可能会有所收获 - 我认为 PHP 不够智能,无法在函数调用之间缓存这些数组。
您还可以将这两个
str_replace
合并为一个:$word = str_replace(array('j','v'), array('i','u'), $word );
,或者,由于您要用单个字符替换单个字符,因此您可以使用$word = strtr($word,'jv','iu');
- 但我我认为这在实践中不会产生太大影响。你必须尝试一下才能确定。As far as I can tell, this follows the algorithm described in your link, and should work correctly. (Apart from the syntax error you have in the definition of
$suffixesA
- you're missing a couple of apostrophes.)Performance-wise, it doesn't look like there's much to gain here, but there are a few things that come to mind.
If this is going to get called many times during a single execution of the script, there might be something gained by defining these arrays outside of the function - I don't think PHP is smart enough to cache those arrays between calls to the function.
You can also combine those two
str_replace
s into one:$word = str_replace(array('j','v'), array('i','u'), $word);
, or, since you're replacing single characters with single characters, you can use$word = strtr($word,'jv','iu');
- but I don't think that will make much difference in practice. You'll have to try it out to be certain.