我刚刚找到了same_text函数,并且一直在使用它,但是输出百分比总是令我惊讶。请参阅下面的示例。
我试图找到有关在php:similar_text() Docs 上使用的算法的信息:
similar_text()
<?php $p = 0; similar_text('aaaaaaaaaa', 'aaaaa', $p); echo $p . "<hr>"; //66.666666666667 //Since 5 out of 10 chars match, I would expect a 50% match similar_text('aaaaaaaaaaaaaaaaaaaa', 'aaaaa', $p); echo $p . "<hr>"; //40 //5 out of 20 > not 25% ? similar_text('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'aaaaa', $p); echo $p . "<hr>"; //9.5238095238095 //5 out of 100 > not 5% ? //Example from PHP.net //Why is turning the strings around changing the result? similar_text('PHP IS GREAT', 'WITH MYSQL', $p); echo $p . "<hr>"; //27.272727272727 similar_text('WITH MYSQL', 'PHP IS GREAT', $p); echo $p . "<hr>"; //18.181818181818 ?>
谁能解释这是如何工作的?
更新:
多亏了这些评论,我发现该百分比实际上是使用相似字符的数量* 200 /长度1 +长度2计算得出的
Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len);
因此,这解释了为什么敏锐度高于预期的原因。对于95中有5个的字符串,结果为10,所以我可以使用。
similar_text('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'aaaaa', $p); echo $p . "<hr>"; //10 //5 out of 95 = 5 * 200 / (5 + 95) = 10
但是我仍然不知道为什么PHP在翻转字符串时会返回不同的结果。dfsq提供的JS代码不会执行此操作。查看PHP中的源代码,我只能在以下几行中找到不同之处,但我不是交流程序员。一些区别的见解,将不胜感激。
在JS中:
for (l = 0;(p + l < firstLength) && (q + l < secondLength) && (first.charAt(p + l) === second.charAt(q + l)); l++);
在PHP中:(php_similar_str函数)
for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
资源:
/* {{{ proto int similar_text(string str1, string str2 [, float percent]) Calculates the similarity between two strings */ PHP_FUNCTION(similar_text) { char *t1, *t2; zval **percent = NULL; int ac = ZEND_NUM_ARGS(); int sim; int t1_len, t2_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Z", &t1, &t1_len, &t2, &t2_len, &percent) == FAILURE) { return; } if (ac > 2) { convert_to_double_ex(percent); } if (t1_len + t2_len == 0) { if (ac > 2) { Z_DVAL_PP(percent) = 0; } RETURN_LONG(0); } sim = php_similar_char(t1, t1_len, t2, t2_len); if (ac > 2) { Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len); } RETURN_LONG(sim); } /* }}} */ /* {{{ php_similar_str */ static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max) { char *p, *q; char *end1 = (char *) txt1 + len1; char *end2 = (char *) txt2 + len2; int l; *max = 0; for (p = (char *) txt1; p < end1; p++) { for (q = (char *) txt2; q < end2; q++) { for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++); if (l > *max) { *max = l; *pos1 = p - txt1; *pos2 = q - txt2; } } } } /* }}} */ /* {{{ php_similar_char */ static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2) { int sum; int pos1, pos2, max; php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max); if ((sum = max)) { if (pos1 && pos2) { sum += php_similar_char(txt1, pos1, txt2, pos2); } if ((pos1 + max < len1) && (pos2 + max < len2)) { sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max, txt2 + pos2 + max, len2 - pos2 - max); } } return sum; } /* }}} */
Javascript中的源代码:与 JavaScript 类似的文本端口
看起来函数确实根据参数顺序使用了不同的逻辑。我认为有两件事在起作用。
首先,请参见以下示例:
echo similar_text('test','wert'); // 1 echo similar_text('wert','test'); // 2
似乎正在测试“在param2中找到param1的任何不同字符的次数”,因此,如果在周围交换参数,结果将有所不同。据报道,它是一个错误,已被关闭为“按预期工作”。
现在,以上对于PHP和javascript实现都是 相同 的-参数表顺序会产生影响,因此说JS代码不会执行此操作是错误的。在Bug条目中认为这是预期的行为。
其次-看起来不正确的是MYSQL / PHP单词示例。这样,javascript版本给出了3个与参数顺序无关的参数,而PHP提供了2个和3个参数(由于这个原因,百分比也同样不同)。现在,短语“ PHP IS GREAT”和“ WITH MYSQL”应该共有5个字符,这与您进行比较的方式无关:H,I,S和T,每个字符一个,再加上一个空格。为了使它们具有3个字符,分别为“ H”,“’和’S”,因此,如果您查看顺序,则正确的答案应该是两种方式都为3。我将C代码修改为可运行的版本,并添加了一些输出,因此可以看到那里发生了什么(codepad link):
#include<stdio.h> /* {{{ php_similar_str */ static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max) { char *p, *q; char *end1 = (char *) txt1 + len1; char *end2 = (char *) txt2 + len2; int l; *max = 0; for (p = (char *) txt1; p < end1; p++) { for (q = (char *) txt2; q < end2; q++) { for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++); if (l > *max) { *max = l; *pos1 = p - txt1; *pos2 = q - txt2; } } } } /* }}} */ /* {{{ php_similar_char */ static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2) { int sum; int pos1, pos2, max; php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max); if ((sum = max)) { if (pos1 && pos2) { printf("txt here %s,%s\n", txt1, txt2); sum += php_similar_char(txt1, pos1, txt2, pos2); } if ((pos1 + max < len1) && (pos2 + max < len2)) { printf("txt here %s,%s\n", txt1+ pos1 + max, txt2+ pos2 + max); sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max, txt2 + pos2 + max, len2 - pos2 - max); } } return sum; } /* }}} */ int main(void) { printf("Found %d similar chars\n", php_similar_char("PHP IS GREAT", 12, "WITH MYSQL", 10)); printf("Found %d similar chars\n", php_similar_char("WITH MYSQL", 10,"PHP IS GREAT", 12)); return 0; }
结果输出:
txt here PHP IS GREAT,WITH MYSQL txt here P IS GREAT, MYSQL txt here IS GREAT,MYSQL txt here IS GREAT,MYSQL txt here GREAT,QL Found 3 similar chars txt here WITH MYSQL,PHP IS GREAT txt here TH MYSQL,S GREAT Found 2 similar chars
因此,可以看到,在第一个比较中,该函数找到了“ H”,“”和“ S”,但没有找到“ T”,并得到了3的结果。第二个比较发现了“ I”和“ T”,但没有找到’H’,’‘或’S’,因此得到2的结果。
从输出中可以看到产生这些结果的原因:算法从第二个字符串包含的第一个字符串中取出第一个字母,对其进行计数, 然后从第二个字符串中丢弃之前的char 。这就是为什么它错过了中间的字符,这就是在更改字符顺序时引起差异的原因。
发生的事情可能是故意的,也可能不是故意的。但是,这不是javascript版本的工作方式。如果您在javascript版本中打印出相同的内容,则会得到以下信息:
txt here: PHP, WIT txt here: P IS GREAT, MYSQL txt here: IS GREAT, MYSQL txt here: IS, MY txt here: GREAT, QL Found 3 similar chars txt here: WITH, PHP txt here: W, P txt here: TH MYSQL, S GREAT Found 3 similar chars
显示javascript版本以不同的方式实现。javascript版本的作用是在第一次比较中发现’H’,’‘和’S’的顺序相同,而在第二次比较中发现相同的’H’,’‘和’S’-因此在这种情况下,参数的顺序无关紧要。
由于javascript旨在复制PHP函数的代码,因此其行为必须相同,因此我根据对@Khez和该修复程序的分析提交了错误报告,该错误报告现已合并。