我们尝试从一组已知单词 ( ) 中将域名 ( s
) 拆分为任意数量的单词(不仅仅是 2 个words
)。递归ftw!
def substrings_in_set(s, words):
if s in words:
yield [s]
for i in range(1, len(s)):
if s[:i] not in words:
continue
for rest in substrings_in_set(s[i:], words):
yield [s[:i]] + rest
这个迭代器函数首先产生调用它的字符串,如果它在words
. 然后它以各种可能的方式将字符串分成两部分。如果第一部分不在 中words
,它会尝试下一个拆分。如果是,则第一部分会添加到在第二部分调用自身的所有结果之前(可能没有,如 ["example", "cart", ...])
然后我们构建英语词典:
# Assuming Linux. Word list may also be at /usr/dict/words.
# If not on Linux, grab yourself an enlish word list and insert here:
words = set(x.strip().lower() for x in open("/usr/share/dict/words").readlines())
# The above english dictionary for some reason lists all single letters as words.
# Remove all except "i" and "u" (remember a string is an iterable, which means
# that set("abc") == set(["a", "b", "c"])).
words -= set("bcdefghjklmnopqrstvwxyz")
# If there are more words we don't like, we remove them like this:
words -= set(("ex", "rs", "ra", "frobnicate"))
# We may also add words that we do want to recognize. Now the domain name
# slartibartfast4ever.co.uk will be properly counted, for instance.
words |= set(("4", "2", "slartibartfast"))
现在我们可以把事情放在一起:
count = {}
no_match = []
domains = ["examplecartrading.com", "examplepensions.co.uk",
"exampledeals.org", "examplesummeroffers.com"]
# Assume domains is the list of domain names ["examplecartrading.com", ...]
for domain in domains:
# Extract the part in front of the first ".", and make it lower case
name = domain.partition(".")[0].lower()
found = set()
for split in substrings_in_set(name, words):
found |= set(split)
for word in found:
count[word] = count.get(word, 0) + 1
if not found:
no_match.append(name)
print count
print "No match found for:", no_match
结果:{'ions': 1, 'pens': 1, 'summer': 1, 'car': 1, 'pensions': 1, 'deals': 1, 'offers': 1, 'trading': 1, 'example': 4}
使用 aset
来包含英语词典可以进行快速的成员资格检查。-=
从集合中删除项目,|=
添加到它。
将all
函数与生成器表达式一起使用可以提高效率,因为all
返回第一个False
.
一些子字符串可能是一个整体或拆分的有效单词,例如“example”/“ex”+“ample”。对于某些情况,我们可以通过排除不需要的词来解决问题,例如上面代码示例中的“ex”。对于其他的,比如“pensions”/“pens”+“ions”,可能是无法避免的,当发生这种情况时,我们需要防止字符串中的所有其他单词被计算多次(一次用于“pensions”,一次用于对于“笔”+“离子”)。我们通过跟踪在集合中找到的每个域名的单词来做到这一点——集合忽略重复项——然后在找到所有单词后对单词进行计数。
编辑:重组并添加了很多评论。强制字符串为小写以避免因大写而丢失。还添加了一个列表来跟踪没有单词组合匹配的域名。
NECROMANCY 编辑:更改了子字符串函数,以便更好地扩展。对于超过 16 个字符左右的域名,旧版本变得异常缓慢。仅使用上面的四个域名,我将自己的运行时间从 3.6 秒提高到了 0.2 秒!