如何區分一串字元是亂碼還是英文或是拼音?

有沒有什麼辦法判斷一段任意長度文字可能是亂碼還是拼音還是英文?比如thejdlasjdiuchdlajsld可能是一段亂碼,WhenIwrotethefollowingpagesorratherthebulkofthem是英文,zheshiyiduanpinyin是拼音?不要求百分之百判斷出來,只要能較大概率判斷正確就行。

我認為目前的問題有兩個方向:

方向1,短字元串,可以採用窮舉對應的方法。

方向2,長的段落,可以採用統計字元頻率的方法。

請問是否有更好的方法來解決這個問題?


比較簡單又有效的方法是統計各種連續2、3個字母的組合(即字母的bigram、trigram)出現的頻率,與標準的英文、拼音資料庫對比。可以採用KL-divergence作為定量比較的標準。

這裡利用的主要是拼音和英語的phonotactics(字母組合規律)的顯著差異。


拼音因為有十分準確的規律,音節固定為聲母(輔音字元拼成,可能沒有)+韻母組合,因此判斷一串字元是否可能是拼音是明確有規律的。可以劃分成音節並且沒有出現連續聲母,沒有出現不適合獨立出現的多韻母(如i),足夠了。

英文的話,如果文字夠長,粗判用詞頻是沒問題的。短短几十幾百個字母則肯定不行。你需要有個比較完整的詞庫,然後做個諸如DP甚至貪心一類的匹配,算匹配概率就好。當然也可以分詞,只不過略微顯得有些大材小用。

「亂碼」則是但凡識別不出來就算咯……


看了這麼多回答,沒一個說用隨機法的么?

隨機取一個字母,以它為中心,判斷能否和兩端構成英文單詞或者拼音,單詞長度不超過10就好 。

重複以上過程m次,假設性檢驗的方法很容易得出 出錯概率<0.0001的結論吧唧


拼音很好弄,而且能100%,網上隨便就有全部合法拼音的list,比如全部漢語拼音組合

然後從前向後做動態規劃。能找到一條合法路徑就能百分百確定是拼音。

英文稍微麻煩一點,你首先需要一個帶頻率/概率的英文詞表。當然這個網上也遍地都是。比如https://books.google.com/ngrams。注意詞表應包含26個單獨字母,否則你遇到詞表沒有的詞很可能抓瞎。

然後依然從前向後做動態規劃,每次使用概率最大的路徑,然後根據最後得出路徑里的英文單詞平均長度來看,亂碼串應該是1-2之間,大一些應該是英文。但是短串這麼判斷可能不準確,可以根據整個句子的信息熵來判斷。


你的問題分為2類:

1:是否包含亂碼

2:區分拼音和英文

第一個問題,通常是使用了錯誤的編碼去講位元組數據轉換為字元串導致的。(有時候是錯誤的將不同編碼的位元組數據混在了一起)

基於這個分析,使用C#可以這樣實現:

效率較低,原理只是檢查byte[]中是否包含與指定編碼不同的數據。

/// &

/// 按照指定編碼檢查給定的位元組數組中是否包含亂碼

/// &

/// &

&

/// &

僅支持UTF8/GB2312/GBK/GB18030編碼檢測&

/// &true表示有亂碼&

public static bool HasGarbageChars(byte[] raw, Encoding encoding)

{

if (raw == null || encoding == null)

throw new Exception("Raw data or Encoding parameter can not be null.");

if (raw.Length == 0)

return false;

int start = 0;

if (raw.Length &>= 3)

{

if (raw[0] == 0xEF raw[1] == 0xBB raw[2] == 0xBF)

start = 3;

}

if (raw.Length &>= 2)

{

if (raw[0] == 0xFF raw[1] == 0xFE)

start = 2;

else if (raw[0] == 0xFE raw[1] == 0xFF)

start = 2;

}

for (int i = start; i &< raw.Length; i++)

{

bool notGB2312 = false;

bool notGBK = false;

if (encoding == GBKEncoding || encoding == GB18030Encoding || encoding == GB2312Encoding)

{

if (raw[i] &>= 0xb0 raw[i] &<= 0xf7) //gb2312

{

if (i + 1 &< raw.Length)

{

if (!(raw[i + 1] &>= 0xa1 raw[i + 1] &<= 0xfE))

{

if (encoding == GB2312Encoding)

return true;

else

notGB2312 = true;

}

else

{

i += 1;

continue;

}

}

else

return true;

}

}

if ((encoding == GB18030Encoding || encoding == GBKEncoding) notGB2312)

{

if (i + 1 &< raw.Length)

{

if (!(raw[i] &>= 0x81 raw[i] &<= 0xA0) (raw[i + 1] &>= 0x40 raw[i + 1] &<= 0xFE) //(1) GBK/3: 8140-A0FE。收錄 GB 13000.1 中的 CJK 漢字 6080 個。

!(raw[i] &>= 0xAA raw[i] &<= 0xFE) (raw[i + 1] &>= 0x40 raw[i + 1] &<= 0xA0) //(2) GBK/4: AA40-FEA0。收錄 CJK 漢字和增補的漢字 8160 個。

!(raw[i] &>= 0xA1 raw[i] &<= 0xA9) (raw[i + 1] &>= 0xA1 raw[i + 1] &<= 0xFE) //a. GB 2312 非漢字元號區。即 GBK/1: A1A1-A9FE。

!(raw[i] &>= 0xA8 raw[i] &<= 0xA9) (raw[i + 1] &>= 0x40 raw[i + 1] &<= 0xA0) // b. GB 13000.1 擴充非漢字區。即 GBK/5: A840-A9A0。

!(raw[i] &>= 0xAA raw[i] &<= 0xAF) (raw[i + 1] &>= 0xA1 raw[i + 1] &<= 0xFE) //用戶自定義區 (1) AAA1-AFFE,碼位 564 個。

!(raw[i] &>= 0xF8 raw[i] &<= 0xFE) (raw[i + 1] &>= 0xA1 raw[i + 1] &<= 0xFE) //用戶自定義區 (2) F8A1-FEFE,碼位 658 個。

!(raw[i] &>= 0xA1 raw[i] &<= 0xA7) (raw[i + 1] &>= 0x40 raw[i + 1] &<= 0xA0)) //用戶自定義區  (3) A140-A7A0,碼位 672 個。

{

if (encoding == GB2312Encoding || encoding == GBKEncoding)

return true;

else

notGBK = true;

}

else

{

i += 1;

continue;

}

}

}

if (encoding == GB18030Encoding notGBK notGB2312)

{

if (raw[i] &>= 0x81 raw[i] &<= 0xfe)

{

if ((i + 3 &< raw.Length) !((raw[i + 1] &>= 0x30 raw[i + 1] &<= 0x39) (raw[i + 2] &>= 0x81 raw[i + 2] &<= 0xFE) (raw[i + 3] &>= 0x30 raw[i + 3] &<= 0x39)))

{

return true;

}

else

{

i += 3;

continue;

}

}

}

if (encoding == Encoding.UTF8)

{

int c = GetByte1Count(raw[i]);

if (c == 0)

continue;

if (c + i &> raw.Length)

return true; //中途截斷

for (int j = 1; j &< c; j++)

{

if ((raw[i + j] &>&> 6) != 2)

{

return true;

}

else

{

if (j == c - 1)

{

i += j;

}

}

}

}

}

return false;

}

第二個問題,不去說什麼語言語義分析,機器學習之類的東西。最簡單的就是白名單。

中文的讀音是有限的,且並不多。可以將所有拼音拼寫作為白名單存起來,拿到的字元串按照白名單對比,即可得到拼音和非拼音單詞的百分比,設置一個閾值來決定是拼音還是英文即可。

剩下來的就是分詞,因為你沒有空格來分詞,所有都是合在一起的。那麼可以按照首字母去拼音白名單里與相同首字母的詞做對比(首字母確定數量就很少了),找得到就去掉整個單詞,下一個字母繼續。如果找不到那就是英文單詞,去掉當前字母,取下一個字母繼續。


基本上的思路是模式識別,諸如隱馬爾科夫,貝葉斯都是常見的可用演算法。

思路很簡單,但做起來很麻煩,我司說要做中日韓越人名的英文識別分類,說了好幾年了,論文讀了一茬又一茬,到現在也沒人去做。。。


統計字元頻率已經會比較准了。

嘗試一下分詞就可以了,不需要窮舉的。拼音分詞挺簡單的,英文分詞有個比較全的字典也不難。


用詞庫,分詞系統都有


一般來說輔音數目在兩個以上並且不是縮寫的很可能是亂碼,string這種不算,所以啊,你們自己也要判斷,把string當成亂碼,等於說,你們也有責任吧?


自然語言中的分詞系統,拼音可以直接分,英語似乎也是有詞典可以直接做的。


力不從心,無法回答。


對題主的方向2補充一下,我也是突然想到的一個。如果是長文本,看分布的話可以用bootstrap來做假設檢驗,從文中抽然後看更偏向於英文還是單詞。


這個真是頭痛啊,


看韻母和聲母出現的頻率


聲母開頭的就是漢語拼音


作為一個外行,我覺得可以搞一個資料庫,資料庫里放英文和漢語拼音的常用詞,比如英語的介詞,連詞。 漢語拼音中的 「de」 「le」 「he」之類的詞,之後就把字元串和兩個資料庫相匹配,分析統計其中詞語的出現概率

_(┐「ε:)_

不知道有沒有幫助,求各路大神鞭打


推薦閱讀:

新手剛接觸編程怎樣去學習比較好?
作為一個什麼都不懂的初學者,應當從哪裡開始學習編程?
如何選擇業餘學習編程的方向?
你們是如何成為編程大牛的?
一個合格的 Python 程序員應該具備怎樣的基本能力?包括哪些具體方面?

TAG:語言 | 演算法 | 編程 | 程序 |