检查字符串是否为姓名的可能缩写
我正在尝试开发一个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)"
而不是 ".*"
,缩写中的字符只有在相邻时才能匹配,或者下一个字符出现在新单词的开头时才能匹配。
这样就能正确地将 fck
和 FC Kopenhavn
匹配起来,但 fco
就不行了。不过,将 aik
和 allmanna 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