日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python文本分析的开源工具_重磅开源:TN文本分析语言

發布時間:2024/1/23 python 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python文本分析的开源工具_重磅开源:TN文本分析语言 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

tn是desert(沙漠之鷹)和tan共同開發的一種用于匹配,轉寫和抽取文本的語言(DSL)。并為其開發和優化了專用的編譯器?;谶f歸下降方法和正則表達式,能解析自然文本并轉換為樹和字典,識別時間,地址,數量等復雜序列模式。

github地址:https://github.com/ferventdesert/tnpy

0.設計理由

字符串分析和處理幾乎是每個員程序必備的工作,簡單到分割類似"1,2,3,4"這樣的字符串,稍微復雜一些如字符串匹配,再復雜如編譯和分析SQL語法。字符串幾乎具有無窮的表達能力,解決字符串問題,就解決了計算機90%的問題。

雖然字符串處理如此深入人心,但當分割字符時,本來都是按照逗號分割的,突然出現分號,程序就可能出錯。再如日期處理,每個程序員肯定都對各種奇怪詭異的時間表達方式感到頭疼,處理起來非常費時。這些功能,幾乎只能以硬編碼實現。它們是與外界交互的最底層模塊,然而卻如此脆弱。

如何將”一百二十三“轉換為數字?

如何將”2013年12月14日“識別為時間并轉換為時間類型?

如何分析一個XML或JSON文件?

正則表達式雖提供了強大的匹配功能,成為必備的工具,但它有不少局限,我們擴展了正則表達式引擎,使之能力大大增強。

在線演示:http://www.desertlambda.com:81/extracttext.html

1. 如何學習?

基本上程序員都讀過“30分鐘學會正則表達式”這篇文章吧?最后沒幾個人能在30分鐘內就讀完它。不過相信我,TN引擎只需要15分鐘就可以學會。

詳細的語法說明在這里:

[tn基本語法][1]

[使用tn構造自然語言計算器][2]

[tn實現的xml解析器][3]

TN可以實現文本的匹配,轉寫和信息抽取,可以理解為模板引擎的逆運算。簡單的操作用正則表達式更方便,但不少問題是正則無法解決的。這時就需要使用TN了。

TN的解釋器有Python,C#和C三種版本。C#版本已經不再維護。使用C#或Java等語言的,建議使用IronPython或Jython進行跨語言編譯。

tnpy是tn的Python解釋器,Python良好的可讀性讓代碼寫起來非常方便,代碼不超過1000行,單文件,無第三方庫依賴。推薦使用Python3。

tn是解釋型語言,需要編寫規則文件,并使用tnpy加載,再對文本進行處理。

1. 基礎的匹配和替換:

首先我們先編寫一個最簡單的規則文件learn,內容如下:

#%Order% 1

hello= ("你好");

接著,執行下面的python代碼:

from src.tnpy import RegexCore

core = RegexCore('../rules/learn')

matchs=core.Match('領導你好!老婆你好');

for m in matchs:

print('match',m.mstr, 'pos:',m.pos)

引入tnpy命名空間,之后從learn規則文件初始化引擎,匹配該文本:

success load tn rules:../rules/learn

match 你好 pos: 2

match 你好 pos: 7

上面輸出了文本的匹配結果和位置。當然這一點正則也能做到。

如果我們匹配的是領導你好,老婆您好,并想把所有的你好和您好,都轉寫為hello。

為此我們添加hello2和hello3兩個子規則:

hello2= $(hello)| ("您好");

#%Order% 1

hello3= $(hello2) : (//:/hello/);

hello2引用了剛才的hello規則,同時添加了“您好”。

hello3是主規則,負責將將hello2匹配的內容都轉寫為hello

($代表引用一條規則,|表示將幾個規則并列排列,匹配最長的那個規則,:代表轉寫。)

執行下面的代碼:`

print(core.Rewrite('領導你好!老婆您好'));

結果為:

領導hello!老婆hello

如果我們想替換順序,把“你好”放在前面呢?可以這樣寫:

people= ("老婆") | ("領導");

#%Order% 1

reorder= $(people) $(hello3) : $2 $1;

先用people定義如何描述老婆,領導,然后用reorder來修改順序, 注意reorder是個順序結構,people匹配老婆和領導,hello3匹配您好/你好,并將其轉換為hello。 $2和$1修改了轉寫順序,執行Rewrite后輸出:

hello領導!hello老婆

我們把類似$(name1) $(name2)的結構,稱為順序表達式,把$(name1) | $(name2)稱為或表達式。

如果將剛才所有的規則繪制成圖,則是下面的樣子:

![foo.png-34.5kB][4]

2. 正則表達式

僅僅使用文本,表現力太差了。我們引入正則表達式來完成,正則表達式需要放在(//)中,注意和文本("")的區別。

如果要進行轉寫,則標注為(/match/:/rewrite/);

下面的表達式將所有的長空白符轉換為一個空白符:

byte_det_space = (/ */://);

下面將所有字母轉換為空白:

low_letter_to_null = (/[a-z]/ ://);

#或者下面:

low_letter= (/[a-z]/);

translate= $(low_letter) : ("");

覺得沒有挑戰?我們接著看下面的。

3. 復雜組合:中文數字轉阿拉伯數字

二十三如何轉換為23?這種用普通的編程會比較困難。我們嘗試用TN解決,會發現一點都不難。

先定義漢字的一二三到九轉換為1-9,你肯定會寫出這樣的規則:

#定義0-9

int_1 = ("一" : "1");

int_0 =("零" : "0");

int_2 = ("二" : "2") | ("兩" : "2");

int_3_9 = ("三" : "3") | ("四" : "4") | ("五" : "5") | ("六" : "6") | ("七" : "7") | ("八" : "8") | ("九" : "9");

int_1_9 = $(int_1) | $(int_2) | $(int_3_9) | (/\d/);

int_0_9 = $(int_0) | $(int_1_9);

int_del_0 = (/零/ : /0/) | (// : /0/);

int_0_9_null = $(int_del_0) | $(int_0_9);

之所以要把0,1,2分開寫,是因為這些數有特殊情況,如兩和二都代表2,需要在后面特殊處理。

上面的int_0_9_null規則,就可以把五七零二轉寫為5702。但沒法處理二十三這樣的情況。

再定義下面的規則,這樣一十三可以轉寫為13

int_del_0 = (/零/ : /0/) | (// : /0/);

int_0_9_null = $(int_del_0) | $(int_0_9);

#定義10,十

int_1_decades = (/十/ : /1/) | (/一十/ : /1/);

再加上下面的規則,int_1_9_decades定義了十位數如何轉寫,而int_10_99定義了從十到九十九的轉寫規則。

int_10_99 = $(int_1_9_decades) $(int_0_9_null) | (/[1-9][0-9]/) ;

int_1_99 = $(int_1_9) | $(int_10_99) ;

int_01_99 = $(int_1_9) | $(int_10_99) | (/\d{1,2}/);

#%Order% 3

int_0_99 = $(int_0) | $(int_1_9) | $(int_10_99);

看看下面的例子:

print({r:core.Rewrite(r) for r in ['十','三十七','一十三','68']});

運行結果:

{'一十三': '13', '68': '68', '十': '10', '三十七': '37'}

是不是感到很神奇?三十七是如何被轉寫為37的?

仔細看規則,規則自底向上構造成了一棵規則樹,in_0_99是整棵樹的根節點。結構如下圖:

![foo.png-132.1kB][5]

下面的log文件給出了匹配過程:

int_0_99,Table,Raw =三十七

int_0,String,Raw =三十七

int_0,String,NG

int_1_9,Table,Raw =三十七

int_1,String,Raw =三十七

int_1,String,NG

int_2,Table,Raw =三十七

int_2_merge,Regex,Raw =三十七

int_2_merge,Regex,NG

int_2,Table,NG

int_3_9,Table,Raw =三十七

int_3_9_merge,Regex,Raw =三十七

int_3_9_merge,Regex,Match=三

int_3_9,Table,Match=三

int_1_9_3,Regex,Raw =三十七

int_1_9_3,Regex,NG

int_1_9,Table,Match=三

int_10_99,Table,Raw =三十七

int_10_99_0,Sequence,Raw =三十七

int_1_9_decades,Table,Raw =三十七

int_1_decades,Table,Raw =三十七

int_1_decades_0,Regex,Raw =三十七

int_1_decades_0,Regex,Match=十

int_1_decades_1,Regex,Raw =三十七

int_1_decades_1,Regex,NG

int_1_decades,Table,Match=十

int_1_9_decades_1,Sequence,Raw =三十七

int_1_9,Table,Raw =三十七

int_1_9,Table,Buff =三

unknown,Regex,Raw =十七

unknown,Regex,Match=十

int_1_9_decades_1,Sequence,Match=三十

int_1_9_decades,Table,Match=三十

int_0_9_null,Table,Raw =七

int_del_0,Table,Raw =七

int_del_0_0,Regex,Raw =七

int_del_0_0,Regex,NG

int_del_0_1,Regex,Raw =七

int_del_0_1,Regex,Match=

int_del_0,Table,Match=

int_0_9,Table,Raw =七

int_0,String,Raw =七

int_0,String,NG

int_1_9,Table,Raw =七

int_1,String,Raw =七

int_1,String,NG

int_2,Table,Raw =七

int_2_merge,Regex,Raw =七

int_2_merge,Regex,NG

int_2,Table,NG

int_3_9,Table,Raw =七

int_3_9_merge,Regex,Raw =七

int_3_9_merge,Regex,Match=七

int_3_9,Table,Match=七

int_1_9_3,Regex,Raw =七

int_1_9_3,Regex,NG

int_1_9,Table,Match=七

int_0_9,Table,Match=七

int_0_9_null,Table,Match=七

int_10_99_0,Sequence,Match=三十七

int_10_99_1,Regex,Raw =三十七

int_10_99_1,Regex,NG

int_10_99,Table,Match=三十七

int_0_99,Table,Match=三十七

引擎從文本的左向右,沿著規則樹尋找最長的文本,如果在一個順序表達式上的任何一步失敗,那么整個順序表達式被拋棄?;虮磉_式會遍歷每個子表達式,直到發現最長的那個,返回結果。具體的匹配原理,以及優化,會在專門的文章中介紹。

4. 由規則構造更復雜的規則

自然而然的,知道怎么定義三十七,就可以定義五百三十七,那不過是int_1_9_hundreds+int_0_99(這個已經定義過了)。

int_1_9_hundreds = $(int_1_9) ("百" : "");

int_100_999 = $(int_1_9_hundreds) ("" : "00") | $(int_1_9_hundreds) $(int_10_99);

int_1_999 = $(int_1_99) | $(int_100_999);

int_1_999可以處理類似五百三十七這樣的問題!

進而,我們可以處理幾千,幾萬,這個延伸到萬以后,就可以自然而然地衍生出億,萬億的表達。

如何處理負數?這還不簡單!

signed_symbol0 = ("正" : "") | ("負" : "-") | ("正負" : "±") | ("\+" : "+") | ("\-" : "-") | ("±" : "±") ;

signed_symbol = $(signed_symbol0) | $(null_2_null);

接下來,我們默認正整數為integer_int,那么,整數(包含正負)就是:

integer_signed = $(signed_symbol) $(integer_int)

5. 屬性提取

沿著剛才的路,我們自然而然地能定義分數,但僅僅是轉寫還不夠,遇到三分之一,我們不僅要將其處理為1/3,還要計算出它的值,這就涉及到屬性抽取。也就是把信息從文本中提取為字典。

分數,不過是整數+分之+整數,可以定義成下面的形式:

fraction_cnv_slash = ("分之" : "/");

fraction2 = ("/" : "/");

percent_transform= ("%" : "100") | ("‰" : "1000");

#%Type% DOUBLE

#%Property% Denominator,,Numerator| Numerator ,, Denominator | Denominator ,, Numerator

#%Order% 101

fraction = $(integer_int_extend) $(fraction_cnv_slash) $(integer_int) : $3 $2 $1

| $(integer_int) $(fraction2) $(integer_int)

| $(pure_decimal) ("" : "/") $(percent_transform);

這個有點復雜,但容我慢慢講解。分數有三種情況,如剛才的三分之一,或是1/3,或是30%。分別對應上面fraction規則的三個子規則。仔細地看上面的規則,不難理解。

值得注意的是Property這個標簽,該標簽定義了如何抽取信息。也是用豎線分隔,每個名稱對應下面的一個子規則,為空的直接跳過。那么”十三分之二十四“中,“十三”就對應Numerator, 而“二十四”對應Denominator。來測試一下:

print(core.Extract('十三分之二十四',entities=[core.Entities['fraction']]))

我們用Extract函數來抽取文本,返回的是一個字典,entites是可選參數,我們限制只用fraction規則來匹配,獲得輸出:

'#match': '十三分之二十四', 'Denominator': '13', '#pos': 3}]```

是不是很贊?

###6.嵌入Python腳本

有一種需求還沒談到,將所有的大寫字母轉換為小寫字母,你可能會想定義26個字符串規則,并用或表達式來拼接起來吧?這樣太費事了。我們可以直接這樣:

`low_to_up_letter = (/[A-Z]/) : "str.lower(mt)";`

`[A-Z]`匹配了所有的大寫字母,將匹配結果送到后半段的轉寫,內置的解釋器會執行那段python代碼,將其轉換為小寫,mt代表前面表達式的匹配串,rt代表轉寫串。好在`[A-Z]`不執行轉寫,可以認為`mt==rt`.

這是在轉寫過程中嵌入python的例子,還能在匹配時嵌入轉寫:

`foo = "findsecret" : "print(mt)"`;

前面的findsecret函數負責在字符串中找到“神秘文本”,后面的轉寫代碼打印出來,并將原始的字符返回…

##6. 你在15分鐘內讀完了么?

我相信你沒有,因為讀懂那個匹配規則的日志文件,就需要最少五分鐘,但如果你有編譯原理和正則基礎的話,還是能很快理解的。而從零開發這個引擎,到反復優化和完善,花了一年之久。

定義了各種數字之后,我們就能很快地定義時間,日期,電話號碼,地址…而你看到的只是TN語言的冰山一角。

- 它能夠分析文本的模式,解析諸如ABCABC這樣的序列,從而發現這是一個重復模式。

- 不僅能夠順序匹配,還能逆向,甚至亂序匹配,這就能夠抽取類似“學校的校訓”這樣的問題。

- 規則可以調用自身,配合腳本,因此能夠實現遞歸下降解析。例如30行代碼實現xml解析,或20行規則實現自然語言計算器。

- 規則可以嵌入腳本,甚至動態生成代碼,因此,甚至在理論上,TN能夠自己編譯自己。

- TN還能做一個簡單的SQL解釋器,或是中文英文的簡單互相翻譯的工具。

是不是已經激動地顫抖了?唯一限制你能力的就是你的想象力。本博客將會進一步發布一系列有關tn的內容,包括高級語法,tn優化等。

感興趣的可以聯系作者:buptzym@qq.com,或在本文下面留言。

[1]: http://www.cnblogs.com/buptzym/p/5355827.html

[2]: http://www.cnblogs.com/buptzym/p/5361121.html

[3]: http://www.cnblogs.com/buptzym/p/5355920.html

[4]: http://static.zybuluo.com/buptzym/ksl5ggrfcn1psmdf2f81i8wg/foo.png

[5]: http://static.zybuluo.com/buptzym/itwhlmz8ua2h3jgbqdq5z48g/foo.png

總結

以上是生活随笔為你收集整理的python文本分析的开源工具_重磅开源:TN文本分析语言的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。