<p>在<code>fuzzywuzzy</code>库的某个地方有一个非常奇怪和微妙的bug</p>
<p>如果我们运行以下命令</p>
<pre><code>from fuzzywuzzy import fuzz
fuzz.partial_ratio('funny', 'aa aaaaa aaaa aaaaaaa funny aaaaaaa aaaaaaaa aaaaaaa aaaa aaaa aaayaaaa auaa aaaa aaaaaaaa aaaaaaaaa aaaaaa aaaaaaaa aaaaa aaaa aa aaaaaaaaaaa aaaaaa aaaffaaaaaaa aaaaa aaayaaaa auaa funny aaaa aaaaaa')
</code></pre>
<p>它返回<code>0</code></p>
<p>鉴于,如果我们从该字符串的开头删除一个字母:</p>
<pre><code>fuzz.partial_ratio('funny', 'a aaaaa aaaa aaaaaaa funny aaaaaaa aaaaaaaa aaaaaaa aaaa aaaa aaayaaaa auaa aaaa aaaaaaaa aaaaaaaaa aaaaaa aaaaaaaa aaaaa aaaa aa aaaaaaaaaaa aaaaaa aaaffaaaaaaa aaaaa aaayaaaa auaa funny aaaa aaaaaa')
</code></pre>
<p>它返回<code>100</code></p>
<p>(很抱歉,字符串又长又可怕。我已经尝试将其简化为尽可能简单的字符串,但我似乎看不到导致此错误的逻辑)</p>
<p>Github上似乎有<a href="https://github.com/seatgeek/fuzzywuzzy/issues/279" rel="nofollow noreferrer">similar bug reports</a></p>
<p>安装<code>python-Levenshtein</code>似乎修复了我上面的示例(如果未安装<code>python-Levenshtein</code>,FuzzyWzzy将恢复为<code>difflib</code>),但不会更改原始示例</p>
<p>安装了<code>python-Levenshtein</code>后,我可以将您的示例简化为:</p>
<pre><code>fuzz.partial_ratio('sleeve', 's l e e v sleeve e ')
</code></pre>
<p>返回<code>50</code></p>
<p>从较长字符串中删除第一个字母:</p>
<pre><code>fuzz.partial_ratio('sleeve', 'l e e v sleeve e ')
</code></pre>
<p>返回<code>100</code></p>
<p>这为可能发生的事情提供了一些线索,但我怀疑这需要深入<code>python-Levenshtein</code>才能弄清楚</p>
<p>我的推荐?提交错误报告。然后找到另一个库来比较字符串<a href="https://github.com/maxbachmann/rapidfuzz" rel="nofollow noreferrer">RapidFuzz</a>可能是一个合适的替代方案</p>
<p>更新:</p>
<p>我认为这个bug可能与使用<code>python-Levenshtein</code>库中的<code>opcodes</code>有关:</p>
<pre><code>from Levenshtein import opcodes
opcodes('sleeve', 's l e e v sleeve e ')
</code></pre>
<p>返回:</p>
<pre><code>[('equal', 0, 1, 0, 1),
('insert', 1, 1, 1, 2),
('equal', 1, 2, 2, 3),
('insert', 2, 2, 3, 4),
('equal', 2, 3, 4, 5),
('insert', 3, 3, 5, 6),
('equal', 3, 4, 6, 7),
('insert', 4, 4, 7, 8),
('equal', 4, 5, 8, 9),
('insert', 5, 5, 9, 12),
('equal', 5, 6, 12, 13),
('insert', 6, 6, 13, 19)]
</code></pre>
<p>在<code>fuzzywuzzy</code>中使用时,这显然不是预期的结果,即使这是一组最小的编辑操作。在{<cd1>}中,优先权应该放在连续块上,而Levenshtein距离的正式定义并不优先于连续块和非连续块(至少我不这么理解)。注意<code>difflib.SequenceMatcher.get_opcodes()</code>给出了不同的结果</p>
<p>我怀疑需要一些非常仔细的思考来修复这个bug并使其正确</p>