检查字符串是否为姓名的可能缩写

14 投票
5 回答
13776 浏览
提问于 2025-04-17 01:39

我正在尝试开发一个Python算法,用来检查一个字符串是否可以作为另一个词的缩写。举个例子:

  • fck可以和fc kopenhavn匹配,因为它匹配了这个词的首字母。fhk就不匹配。
  • fco不应该和fc kopenhavn匹配,因为现实中没人会把FC Kopenhavn缩写成FCO。
  • irl可以和in real life匹配。
  • ifk可以和ifk goteborg匹配。
  • aik可以和allmanna idrottskluben匹配。
  • aid可以和allmanna idrottsklubben匹配。虽然这不是一个真实的球队名称缩写,但我想除非你对瑞典的缩写规则有特定的了解,否则很难排除这种情况。
  • manu可以和manchester united匹配。

确切的算法规则很难描述,但我希望我的例子能让你明白我想要的是什么。

更新 我之前在展示匹配字母时犯了个错误,显示成了大写。在实际情况下,所有字母都是小写的,所以这并不像简单地检查哪些字母是大写的那么容易。

5 个回答

4

@Ocaso Protal 在评论中提到 你怎么判断 aik 是有效的,而 aid 不是有效的呢? 他说得对。

我想到的一个方法是使用 词阈值(就是用空格分开的单词数量)。

words = string.strip().split()
if len(words) > 2:
   #take first letter of every word
elif len(words) == 2:
   #take two letters from first word and one letter from other
else:
   #we have single word, take first three letter or as you like

你需要定义自己的逻辑,不能盲目地去找缩写。

4

这里有一种方法可以实现你想做的事情。

import re    
def is_abbrev(abbrev, text):
    pattern = ".*".join(abbrev.lower())
    return re.match("^" + pattern, text.lower()) is not None

这个“^”符号确保缩写的第一个字母和单词的第一个字母是一样的,这对大多数缩写来说都是成立的。

编辑:你的新更新稍微改变了一下规则。通过使用 "(|.*\s)" 而不是 ".*",缩写中的字符只有在相邻时才能匹配,或者下一个字符出现在新单词的开头时才能匹配。

这样就能正确地将 fckFC Kopenhavn 匹配起来,但 fco 就不行了。不过,将 aikallmanna idrottskluben 匹配就行,因为这需要对瑞典语有一定了解,操作起来没有那么简单。

这是经过小修改后的新代码。

import re    
def is_abbrev(abbrev, text):
    pattern = "(|.*\s)".join(abbrev.lower())
    return re.match("^" + pattern, text.lower()) is not None
14

这个代码通过了所有测试,包括我自己加的一些额外测试。它使用了递归的方法。以下是我用到的规则:

  • 缩写的第一个字母必须和文本的第一个字母相匹配。
  • 缩写的其余部分(去掉第一个字母后的部分)必须是以下内容的缩写:

    • 剩下的单词,或者
    • 从第一个单词的任何位置开始的剩余文本。

tests=(
    ('fck','fc kopenhavn',True),
    ('fco','fc kopenhavn',False),
    ('irl','in real life',True),
    ('irnl','in real life',False),    
    ('ifk','ifk gotebork',True),   
    ('ifko','ifk gotebork',False),    
    ('aik','allmanna idrottskluben',True),
    ('aid','allmanna idrottskluben',True),
    ('manu','manchester united',True), 
    ('fz','faz zoo',True), 
    ('fzz','faz zoo',True),
    ('fzzz','faz zoo',False),    
    )

def is_abbrev(abbrev, text):
    abbrev=abbrev.lower()
    text=text.lower()
    words=text.split()
    if not abbrev:
        return True
    if abbrev and not text:
        return False
    if abbrev[0]!=text[0]:
        return False
    else:
        return (is_abbrev(abbrev[1:],' '.join(words[1:])) or
                any(is_abbrev(abbrev[1:],text[i+1:])
                    for i in range(len(words[0]))))

for abbrev,text,answer in tests:
    result=is_abbrev(abbrev,text)
    print(abbrev,text,result,answer)
    assert result==answer

撰写回答