2017-02-09 39 views
2

我正在編寫的Python應用程序需要從源代碼中提取標識符和文本字符串。它發現的一小部分是(看似)隨機字符串。我想過濾它們,但到目前爲止還沒有能夠創建一個正則表達式來做到這一點。不可能僅按長度進行過濾,因爲有一些非常長的標識符是有效的。下面是一個例子採取隨機的,與相同長度的有效的標識符:如何匹配實際上是隨機的字符串?

UGxhemEgZGUgaWZXNaWdhZGyOiBDSUWRVNUQVYtSVBOIFVuaWQ 
NSApplicationDidChangeScreenParametersNotification 

是否有寫一個正則表達式或其它檢測系統,該系統將檢測像這樣的垃圾序列的方法嗎?我開始懷疑,如果不測試字符串對大量字詞典的測試是不行的,我認爲這些字典很容易出錯並且計算密集。然而,也許有人更聰明的知道檢測或匹配像這樣的隨機序列的方法?

這個問題的理想解決方案是一個函數,可以將字符串作爲輸入,並報告它是否可能是隨機的。它可能會產生錯誤的否定結果(誤報一些隨機字符串不是隨機的),最好的概率很低,但是不能報告錯誤的肯定結果(當它不是真的時候它是隨機的)。如果重要,字符串的長度範圍可以從25到80個字符。

編輯#1 2017-02-08:進一步思考,我想到一個可能的方法可能是一個正則表達式匹配一行中最小數量的唯一字符。例如,第二個字符必須與第一個不同,第三個不同於前兩個,第四個不同於第三個,等等。足夠長的版本可能會捕獲很多隨機序列。然而,看着不同的正則表達式運算符,我看不到一個版本(缺少更好的單詞)的「負面背景參考」或「匹配其他比你剛剛匹配的東西」。如果有人知道這個變化,也許我可以讓它工作。

編輯#1 2017年2月10日:我很擔心,我寫我的兩個例子字符串的方式上面可能被誤解爲一個字符串。上面的例子是兩個不同長度的字符串,如果不清楚的話,我誠摯的道歉。這裏有更多的例子。每一行都是一個單獨的標識符。這也顯示了不同的長度。

shouldBeAbleToCountLiveNeighboursOfACellOnDiagonalsAndStraightLines 
eXNZWzIGbHRpbWVkaWEgYWkIGFuaWhdGlvbiBkaXNcmlidXRlZCNCpUgRGlzdHJpYnV 
dWxLXRvbGVyYWIHJlYWwtdGltZSBzeXNZWzLgKlSBEaXNcmlidXRlZCBBcmNoaXRlYR 
dGhIExvIHNYmltbMgYSBsYSBwWdpbmEgeSBsbyBhbnVuYlhbWzIGVuIGVsIHByhpbWg 
aGUgYuZmVyZWjZSBwcmjZWVkaWncygDQoNClNYmpcNpbNCkluIGyZGVyIHRvIHN 
YQKUGFyYTogZXNYFyQGluYWlcCteAKQMIExaXMgQSgUGluZWRhDQpDQzogQuYVw 
thehasSizeMatcherShouldMatchACollectionWithExpectedSize 
QycmVvIGRlIERpcVtaWhYnDsgZGUgYWNaXZpZGFkZXMgZGUgbGEg 
NSAppleEventManagerWillProcessFirstEventNotification 
SNMTransformGizmoRotationControllerPerformTransform 
RndkOiBEaWZcnDsgZGUgYudmjYXRvcmlhIFNVTUJVCBlbiBSRUJ 

不管它的價值,我把從大約900 GitHub的倉庫半隨機選擇通過我的應用程序拉引擎收錄a list of the 1000 longest identifiers。它包含真實標識符和隨機字符串。

+0

NLTK可能證明對此有用。 – sytech

+1

假設有效令牌包含英文,無效令牌將有更多的連續4個或更多的輔音。 – swbandit

+0

乍看之下,如果字符串的長度足夠大(25-80也可以),那麼怎麼計算每個字母的頻率並將這個分佈與典型的英語語言進行比較。 –

回答

0

你可以看看依賴馬爾可夫鏈的rrenaud's gibberish detector。您將需要修改給定的代碼以滿足您的需求,因爲您會查找包含非亂碼的亂碼。但它可能有幫助。

這可能是一個很好的開始。

但... 我有一些嘗試自己解決這個問題的樂趣。這可能不是最好的答案,它完全依賴於以大寫字母開頭的每個單詞(基於您給定的測試輸入)。但是,我喜歡玩弄想法以獲得一個好結果的結果,但是在更長的文本(您可能會看到的那種)上會非常慢。

import enchant #Spellchecker 
import re 

endict = enchant.Dict("en_US") 

#Test input... 
instr = 'UGxhemEgZGUgaWZXNaWdhZGyOiBDSUWRVNUQVYtSVBOIFVuaWQNSApplicationDidChangeScreenP arametersNotification' 
outstr = '' 

acceptable_short_words = ['a', 'I', 'if', 'is'] #Any one or two letter words you can think of that are OK. 

#Split the words based on capitals. 
words = re.findall('[A-Z][^A-Z]*', instr) 

def isWord(wordin): 
    if(wordin in acceptable_short_words): 
     return True 
    elif(len(wordin) < 3): 
     return False 

    return endict.check(wordin) 

for w in words: 
    if(isWord(w)): 
     outstr += " " + w 

print(outstr.strip()) 

運行此腳本導致:

I Application Did Change Screen Parameters Notification 

起初,我試圖尋找單詞的字符串。這有不好的結果,因爲它檢測到的詞的單詞(例如:通知還包含單詞「不」,「如果」,「貓」,「在」等) 所以我決定分割的首都,並檢查各元素反對字典。這也不能很好地工作,因爲許多單字母單詞被證明是英語單詞:

U - 形容詞|英式|非正式的:(語言或社交行爲的)特徵或適用於鞋幫社會等級。 ( 「U禮儀」)

誰知道?

所以最後,我決定忽略任何短的話,我不知道(相當多的事實證明),並限制對普通短詞。 我可以進一步使用NLTK或類似的工具以類似於亂碼檢測器的方式檢查單詞對頻率。但它已經做了很多次了,我寧可不要。

+0

感謝您的支持。在上面的示例中,我不確定我的問題的措辭是否清楚地表明,我給出的示例包含2個單獨的字符串,而不是一個跨行的字符串。如果不清楚,我真的很抱歉。我已經爲這個問題添加了一些澄清的編輯,並且還提供了一個指向包含更多示例的pastebin的指針。 – mhucka

2

首先,謝謝你,你的問題讓我感興趣再加上我正在尋找一些有趣的訓練。下面我已經在你的帖子的評論中提到了我的想法,以及@swbandit的想法。通過修改is_rnd函數也可以在代碼中添加任何其他策略。 我已經產生從這裏(https://gist.github.com/jbergantine/2390284)發現短期字典意識字符串(當然這字典是小,可能不具有代表性,但是我用它用於測試目的)。這些字符串在代碼中被認爲是strok。之後,生成相同長度的隨機字符串(strrnd)。我只使用小寫字母,並假定字符串中沒有空格。

函數is_rnd1is_rnd2返回True如果字符串是隨機的。函數is_rnd1檢查最頻繁的英文字符'e'(12.7%)和最罕見的'z'(0.074%)的頻率。但是,在該功能中,頻率的邊界顯着擴大。功能is_rnd2只是檢查@swbandit建議的連續四個輔音的外觀。

在上面所描述的功能的代碼的測試部分用於其在構成strok字數來衡量串的不同長度進行測試。函數is_rnd被調用兩次。首先用strok,然後用隨機字符串。定義字符串隨機與否的錯誤是相加的。

所以這是代碼:

nouns = ['here is a list from gist.github.com/jbergantine/2390284'] 
allch = "abcdefghijklmnopqrstuvwxyz" 

import numpy as np 
import matplotlib.pyplot as plt 
import random, string 
import collections 
import re 

alb = 'etaoinshrdlcumwfgypbvkjxqz' 

def frqlist(s): 
    dic = collections.Counter(s) 
    arr = np.zeros(len(alb)) 
    for key in dic: 
     idx = alb.index(key) 
     arr[idx] = float(dic[key])/float(len(s)) 
    return arr 

def generate_strs(nw=1): 
    strok = ''.join([nouns[random.randrange(0, len(nouns))] 
        for i in range(nw)]) 
    rand_str = lambda n: ''.join([random.choice(string.lowercase) 
         for i in xrange(n)]) 
    strrnd = rand_str(len(strok)) 
    return strok, strrnd 

def is_rnd1(s): 
    fq = frqlist(s) 
    return not (fq[0] > 0.07 and fq[-1] < 0.01) 

def is_rnd2(s): 
    return re.search(r'[^aeiou]{4}', s) 

maxwords = 12 
nprobe = 1000 

is_rnd = is_rnd1 
nwa = [] 
err = [] 
print "Words\t% of errors" 
for nw in range(1, maxwords): 
    errok = 0 
    errrnd = 0 
    for i in range(0, nprobe): 
     strok, strrnd = generate_strs(nw) 
     if is_rnd(strok): 
      errok += 1./nprobe 
     if not is_rnd(strrnd): 
      errrnd += 1./nprobe 
    print nw, "\t", (errok*100. + errrnd*100.)/2. 
    nwa.append(nw) 
    err.append((errok*100. + errrnd*100.)/2.) 

plt.plot(nwa, err) 
plt.show() 

下面是一些結果

For function is_rnd1 
Words % of errors 
1 28.2 
2 20.45 
3 17.15 
4 13.15 
5 13.7 
6 10.65 
7 9.25 
8 7.35 
9 6.5 

For function is_rnd2 (4 consecutive consonants) 
Words % of errors 
1 23.15 
2 13.0 
3 13.55 
4 17.75 
5 22.2 
6 24.35 
7 27.7 
8 30.6 
9 33.25 

For function is_rnd2 (6 consecutive consonants) 
Words % of errors 
1 39.45 
2 20.8 
3 11.9 
4 6.5 
5 4.05 
6 3.05 
7 2.5 
8 1.6 
9 2.0 

對我來說結果很有趣。

UPDATE:

我已經試過機器學習。我用了一個有26個入口和一個出口的神經元。在入口處提供字符串中字符的頻率。如果字符串是隨機的,則輸出爲1,否則爲0。神經元是由下面的類描述:

class Neuron(object): 
    def __init__(self, nin, wt=0.): 
     self.nin = nin 
     self.w = np.full(nin, wt, dtype=np.float32) 
     self.out = 0. 
     self.learnspd = 0.01 

    def result(self, ins): 
     self.out = np.sum(self.w * ins) 
     self.out = 1. if self.out > 0.1 else 0. 
     return self.out 

    def correctw(self, ins, err): 
     self.w = self.w + err*self.learnspd*ins 

確定其學習的過程,實現了神經元neuron = Neuron(len(alb))後:

def learning(neuron, nset, maxwords): 
    for i in xrange(nset): 
     nw = np.random.randint(1, maxwords+1) 
     strok, strrnd = generate_strs(nw) 
     fq = frqlist(strok) 
     neurres = neuron.result(fq) 
     errok = 0.0 - neurres 
     neuron.correctw(fq, errok) 
     fq = frqlist(strrnd) 
     neurres = neuron.result(fq) 
     errrnd = 1.0 - neurres 
     neuron.correctw(fq, errrnd) 

讓我們來學習learning(neuron, nset, maxwords)

Finaly,神經元可用於:

def is_rnd_neuron(s, neuron): 
    fq = frqlist(s) 
    return bool(neuron.result(fq)) 

使用相同的測試步驟描述上面我已經得到了以下結果:

nset = 100 
Words % of errors 
1 50.0 
2 50.0 
3 50.0 
4 50.0 
5 50.0 
6 50.0 
7 50.0 
8 50.0 
9 50.0 
nset = 500 
Words % of errors 
1 20.4 
2 13.25 
3 9.5 
4 5.55 
5 5.95 
6 3.9 
7 3.35 
8 2.55 
9 2.4 
nset = 1000 
Words % of errors 
1 16.95 
2 9.35 
3 4.55 
4 2.4 
5 1.7 
6 0.65 
7 0.4 
8 0.15 
9 0.1 
nset = 5000 
Words % of errors 
1 16.6 
2 7.25 
3 3.8 
4 1.8 
5 1.1 
6 0.5 
7 0.1 
8 0.1 
9 0.05 

我真的很感動有多麼容易被意識到它會產生多好的結果。

+0

@ roman-fursenko真的很酷:-)。我用一個指針指向從隨機選擇的github存儲庫中取出的1000個真正的字符串的pastebin,更新了問題。我計劃儘快嘗試你的代碼。感謝您的詳細努力。 – mhucka

相關問題