在python中,我如何区分人类可读的单词和随机字符串



单词示例:

  1. 百科全书
  2. 画面

随机字符串的示例:

  1. 克克斯博格萨克
  2. 贾盖尼
  3. RNNFDWPM

当然,随机字符串实际上可能是某种语言中的一个单词或看起来像一个单词。但基本上,一个人能够说出它看起来"随机"与否,基本上只是通过检查你是否能够发音。

我试图计算熵来区分这两者,但它远非完美。您还有其他有效的想法和算法吗?

不过,有一个重要的要求,我不能使用像nltk这样的重量级库或使用字典。基本上我需要的是一些在大多数情况下都有效的简单快速的启发式方法。

我开发了一个名为 Nostril 的 Python 3 包,用于解决与 OP 提出的问题密切相关的问题:确定在源代码挖掘期间提取的文本字符串是类/函数/变量/等标识符还是随机乱码。 它不使用字典,但它确实包含一个相当大的 n 元语法频率表来支持其对文本字符串的概率评估。 (我不确定这是否符合"字典"的条件。该方法不检查发音,其专业化可能使其不适合一般单词/非单词检测;尽管如此,也许它对 OP 或其他希望解决类似问题的人有用。

示例:以下代码,

from nostril import nonsense
real_test = ['bunchofwords', 'getint', 'xywinlist', 'ioFlXFndrInfo',
             'DMEcalPreshowerDigis', 'httpredaksikatakamiwordpresscom']
junk_test = ['faiwtlwexu', 'asfgtqwafazfyiur', 'zxcvbnmlkjhgfdsaqwerty']
for s in real_test + junk_test:
    print('{}: {}'.format(s, 'nonsense' if nonsense(s) else 'real'))

将生成以下输出:

bunchofwords: real
getint: real
xywinlist: real
ioFlXFndrInfo: real
DMEcalPreshowerDigis: real
httpredaksikatakamiwordpresscom: real
faiwtlwexu: nonsense
asfgtqwafazfyiur: nonsense
zxcvbnmlkjhgfdsaqwerty: nonsense

警告我不是自然语言专家

假设链接中提到的内容 如果你可以拉德蒂斯,你Msut Be Raelly Smrat是真实的,一个简单的方法是

  1. 有一本英语(我相信它的语言对抗)词典
  2. 创建单词的 python 字典,将键作为字典中单词的第一个和最后一个字符

    words = defaultdict()
    with open("your_dict.txt") as fin:
         for word in fin:
            words[word[0]+word[-1]].append(word)
    
  3. 现在对于任何给定的单词,搜索字典(记住键是单词的第一个和最后一个字符)

    for matches in words[needle[0] + needle[-1]]:
    
  4. 比较字典值中的字符和指针是否匹配

    for match in words[needle[0] + needle[-1]]:
        if sorted(match) == sorted(needle):
             print "Human Readable Word"
    

一个相对较慢的方法是使用difflib.get_close_matches(单词,可能性[,n][,截止])

如果你真的是随机性的衡量标准是可发音性,那么你就进入了语音策略的领域:一种语言中允许的声音序列。正如@ChrisPosser在对您的问题的评论中指出的那样,这些允许的声音序列是特定于语言的。

这个问题只在特定语言中有意义。

无论您选择哪种语言,您都可能会对通过字母本身训练的 n-gram 模型(与通常的方法单词相反)有一些运气。然后,您可以计算特定字符串的分数,并设置一个阈值,在该阈值下,字符串是随机的,超过该阈值的字符串类似于单词。

编辑:有人已经这样做并实际实施了它:https://stackoverflow.com/a/6298193/583834

对我来说

效果很好:

VOWELS = "aeiou"
PHONES = ['sh', 'ch', 'ph', 'sz', 'cz', 'sch', 'rz', 'dz']
def isWord(word):
    if word:
        consecutiveVowels = 0
        consecutiveConsonents = 0
        for idx, letter in enumerate(word.lower()):
            vowel = True if letter in VOWELS else False
            if idx:
                prev = word[idx-1]               
                prevVowel = True if prev in VOWELS else False
                if not vowel and letter == 'y' and not prevVowel:
                    vowel = True
                if prevVowel != vowel:
                    consecutiveVowels = 0
                    consecutiveConsonents = 0
            if vowel:
                consecutiveVowels += 1
            else:
                consecutiveConsonents +=1
            if consecutiveVowels >= 3 or consecutiveConsonents > 3:
                return False
            if consecutiveConsonents == 3:
                subStr = word[idx-2:idx+1]
                if any(phone in subStr for phone in PHONES):
                    consecutiveConsonents -= 1
                    continue    
                return False                
    return True

使用 PyDictionary。您可以使用以下命令安装 PyDictionary。

easy_install -U PyDictionary

现在在代码中:

from PyDictionary import PyDictionary
dictionary=PyDictionary()
a = ['ball', 'asdfg']
for item in a:
  x = dictionary.meaning(item)
  if x==None:
    print item + ': Not a valid word'
  else:
    print item + ': Valid'

据我所知,您可以将PyDictionary用于其他一些语言,然后是英语。

我写这个逻辑来检测字符串中连续元音和辅音的数量。您可以根据语言选择阈值。

def get_num_vowel_bunches(txt,num_consq = 3):
    len_txt = len(txt)
    num_viol = 0
    if len_txt >=num_consq:
        pos_iter = re.finditer('[aeiou]',txt)
        pos_mat = np.zeros((num_consq,len_txt),dtype=int)
        for idx in pos_iter:
            pos_mat[0,idx.span()[0]] = 1
        for i in np.arange(1,num_consq):
            pos_mat[i,0:-1] = pos_mat[i-1,1:]
        sum_vec = np.sum(pos_mat,axis=0)
        num_viol = sum(sum_vec == num_consq)
    return num_viol
def get_num_consonent_bunches(txt,num_consq = 3):
    len_txt = len(txt)
    num_viol = 0
    if len_txt >=num_consq:
        pos_iter = re.finditer('[bcdfghjklmnpqrstvwxz]',txt)
        pos_mat = np.zeros((num_consq,len_txt),dtype=int)
        for idx in pos_iter:
            pos_mat[0,idx.span()[0]] = 1
        for i in np.arange(1,num_consq):
            pos_mat[i,0:-1] = pos_mat[i-1,1:]
        sum_vec = np.sum(pos_mat,axis=0)
        num_viol = sum(sum_vec == num_consq)
    return num_viol

最新更新