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

问题描述 投票:0回答:6

词语示例:

  1. 百科全书
  2. 画面

随机字符串示例:

  1. qxbogsac
  2. jgaynj
  3. rnnfdwpm

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

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

有一个重要的要求,我不能使用像

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

python string random nlp heuristics
6个回答
7
投票

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

2
投票

警告我不是自然语言专家

假设链接中提到的内容If You Can Raed Tihs, You Mut 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(word,possibility[, n][, cutoff])


2
投票

如果你的意思确实是你的随机性度量是可发音性,那么你就进入了语音策略的领域:语言中允许的声音序列。正如 @ChrisProsser 在对你的问题的评论中指出的那样,这些允许的声音序列是特定于语言的。

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

无论您选择哪种语言,您都可能会幸运地使用针对字母本身(而不是单词,这是通常的方法)进行训练的 n 元语法模型。然后,您可以计算特定字符串的分数,并设置一个阈值,低于该阈值的字符串是随机的,高于该阈值的字符串类似于单词。

编辑:有人已经做到了这一点并实际实现了它:https://stackoverflow.com/a/6298193/583834


0
投票

对我来说效果很好:

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

0
投票

使用 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 用于除英语之外的其他语言。


0
投票

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

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
© www.soinside.com 2019 - 2024. All rights reserved.