ドメイン名(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
。次に、文字列をあらゆる方法で2つに分割します。最初の部分がにない場合はwords
、次の分割を試みます。そうである場合、最初の部分は、2番目の部分で自分自身を呼び出したすべての結果の前に付加されます(["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}
を使用しset
て英語の辞書を含めると、メンバーシップのチェックが高速になります。-=
セットからアイテムを削除し、|=
追加します。
関数をジェネレータ式all
と一緒に使用すると、最初のに戻るため、効率が向上します。all
False
一部の部分文字列は、「example」/「ex」+「ample」のように、全体または分割の両方で有効な単語である可能性があります。場合によっては、上記のコード例の「ex」などの不要な単語を除外することで問題を解決できます。「年金」/「ペン」+「イオン」のような他の人にとっては、それは避けられないかもしれません、そしてこれが起こるとき、私たちは文字列の他のすべての単語が複数回カウントされないようにする必要があります(「年金」に対して1回と1回) 「ペン」+「イオン」の場合)。これを行うには、セット内の各ドメイン名で見つかった単語を追跡します(セットは重複を無視します)。次に、すべてが見つかったら単語をカウントします。
編集:再構築され、多くのコメントが追加されました。大文字と小文字によるミスを避けるために、文字列を小文字に強制しました。また、単語の組み合わせが一致しなかったドメイン名を追跡するためのリストを追加しました。
NECROMANCY EDIT:拡張性が向上するように部分文字列関数を変更しました。古いバージョンは、16文字程度より長いドメイン名では途方もなく遅くなりました。上記の4つのドメイン名だけを使用して、自分の実行時間を3.6秒から0.2秒に改善しました。