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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

lua工具库penlight--06数据(一)

發(fā)布時(shí)間:2024/4/13 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 lua工具库penlight--06数据(一) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這篇太長了,分了兩部分。(這個(gè)是機(jī)器翻譯之后我又校對了一下,以后的都這樣,人工翻譯太累了。)

讀數(shù)據(jù)文件

首先考慮清楚,你的確需要一個(gè)自定義的文件讀入器嗎?如果是,你能確定有能力寫好嗎?

正確,穩(wěn)健,快速,當(dāng)如先得把第一項(xiàng)處理好。

Unix世界里常見的數(shù)據(jù)文件夾是配置文件。在Java世界里也被叫做屬性文件。

?#?Read?timeout?in?seconds

read.timeout=10

?

#?Write?timeout?in?seconds

write.timeout=10

?

下面是簡單的Lua的實(shí)現(xiàn):

--?property?file?parsing?with?Lua?string?patterns

props?=?[]

for?line?in?io.lines()?do

?????if?line:find('#',1,true)?~=?1?and?not?line:find('^%s*$')?then

?????????local?var,value?=?line:match('([^=]+)=(.*)')

?????????props[var]?=?value

?????end

end

?

非常簡潔,不過用了字符串匹配技巧,對于讀者來說不易讀懂。

下面是利用Penlight的實(shí)現(xiàn):

require?'pl'

stringx.import()

props?=?[]

for?line?in?io.lines()?do

?????if?not?line:startswith('#')?and?not?line:isspace()?then

?????????local?var,value?=?line:splitv('=')

?????????props[var]?=?value

?????end

end

?

顯然上面的代碼可以自為文檔,而不需要到處寫注釋。它的速度稍微有點(diǎn)慢

,但是事實(shí)上腳本的速度有I/O決定,因此一下優(yōu)化是必須的。

?

讀無結(jié)夠的文本數(shù)據(jù)

文本經(jīng)常是無結(jié)構(gòu)的。pl.input提供了許多簡化操作的函數(shù)。例如統(tǒng)計(jì)文本

中的單詞數(shù)量:

?--?countwords.lua

require?'pl'

local?k?=?1

for?w?in?input.words(io.stdin)?do

?????k?=?k?+?1

end

print('count',k)

?

或者計(jì)算平均數(shù):

?--?average.lua

require?'pl'

local?k?=?1

local?sum?=?0

for?n?in?input.numbers(io.stdin)?do

?????sum?=?sum?+?n

?????k?=?k?+?1

end

print('average',sum/k)

這些腳本可以通過進(jìn)一步排除循環(huán)提高效率。下面這個(gè)例子,使用seq.sum函數(shù)

計(jì)算數(shù)字序列的和。

--?average2.lua

require?'pl'

local?total,n?=?seq.sum(input.numbers())

print('average',total/n)

?

一個(gè)更簡單的例子是,從輸入中提取參數(shù),如下:

--?countwords2.lua

require?'pl'

print('count',seq.count(input.words()))

?

一個(gè)有用的序列生成器要能直接讀取字符串。下面這個(gè)例子計(jì)算文件中每行的數(shù)字和:

--?sums.lua

for?line?in?io.lines()?do

?????print(seq.sum(input.numbers(line))

end

?

讀分隔文件

讀取分隔文件是常有的事,它們或以空格、或者逗號(hào)分隔,或許還有初始的列頭。

如下例:

?EventID????Magnitude????LocationX????LocationY????LocationZ

?981124001????2.0????18988.4????10047.1????4149.7

?981125001????0.8????19104.0????9970.4????5088.7

?981127003????0.5????19012.5????9946.9????3831.2

...

?

input.fields可以提取列,并且可以設(shè)置分隔符(默認(rèn)空格)。

下面是計(jì)算所有事件里x的平均位置:(即上表中的LocationX?

?--?avg-x.lua

require?'pl'

io.read()?--?skip?the?header?line

local?sum,count?=?seq.sum(input.fields?{3})

print(sum/count)

?

input.fields可以提取列,并且可以設(shè)置分隔符(默認(rèn)空格)。

下面是計(jì)算所有事件里x的平均位置:(即上表中的LocationX?

?--?avg-x.lua

require?'pl'

io.read()?--?skip?the?header?line

local?sum,count?=?seq.sum(input.fields?{3})

print(sum/count)

?

input.fields可以使用字段數(shù)或列數(shù),可以從1開始也可以從其它列開始。如果你傳遞一個(gè)字段計(jì)數(shù),你會(huì)得到該計(jì)數(shù)的每個(gè)字段:

?for?id,mag,locX,locY,locZ?in?input.fields?(5)?do

?....

?end

?

input.fields?默認(rèn)會(huì)嘗試將每個(gè)字段轉(zhuǎn)換為數(shù)字。它將跳過不匹配模式的字段,如果任何字段都不能轉(zhuǎn)換為數(shù)字時(shí)會(huì)中止腳本。input.fields第二個(gè)參數(shù)是分隔符,默認(rèn)是空格。如果傳入’?‘,會(huì)匹配?'任意數(shù)目的空格',即?'%s+',你可以使用?任意的Lua?字符串匹配模式。

第三個(gè)參數(shù)是數(shù)據(jù)源,默認(rèn)為標(biāo)準(zhǔn)輸入?(由input.create_getter定義)。它假定數(shù)據(jù)源有一個(gè)read的方法,可以產(chǎn)生下一行,即它是一個(gè)?'類文件'?對象。作為一種特殊情況,一個(gè)字符串,將分成多行:

?>?for?x,y?in?input.fields(2,'?','10?20\n30?40\n')?do?print(x,y)?end

?10??????20

?30??????40

?

注意對于壞的字段,默認(rèn)行為是顯示出錯(cuò)的行號(hào):

?>?for?x,y?in?input.fields(2,'?','10?20\n30?40x\n')?do?print(x,y)?end

?10??????20

?line?2:?cannot?convert?'40x'?to?number

?

Input.fields的這種行為是適當(dāng)?shù)?#xff0c;第四個(gè)可選參數(shù)是一個(gè)選項(xiàng)表:?{no_fail=true}意味著嘗試轉(zhuǎn)換后失敗后,僅返回字符串,而不是向?AWK(譯注:一個(gè)*nix下的文本匹配工具)繼續(xù)運(yùn)行。你有責(zé)任檢查返回的字段的類型。{no_convert=true}是否將所有字段都作為字符串返回。

有時(shí)將整個(gè)數(shù)據(jù)放到內(nèi)存中,會(huì)很有用,如提取的列的操作。Penlight專門為閱讀此類型的數(shù)據(jù),提供了一個(gè)靈活的data解析器。例如看起來像這樣的文件:

?x,y

?10,20

?2,5

?40,50

?

data.read將創(chuàng)建如下的表,每一行創(chuàng)建一個(gè)子表:

?>?t?=?data.read?'test.txt'

?>?pretty.dump(t)

?{{10,20},{2,5},{40,50},fieldnames={'x','y'},delim=','}

?

現(xiàn)在,您可以使用提供的方法來分析返回的表。例如,方法column_by_name返回的列的所有表。

?--?testdata.lua

?require?'pl'

?d?=?data.read('fev.txt')

?for?_,name?in?ipairs(d.fieldnames)?do

?????local?col?=?d:column_by_name(name)

?????if?type(col[1])?==?'number'?then

?????????local?total,n?=?seq.sum(col)

?????????utils.printf("Average?for?%s?is?%f\n",name,total/n)

?????end

?end

?

data.read有點(diǎn)小聰明,默認(rèn)情況下它期望第一行是列名稱,除非其中都是何數(shù)字。它會(huì)嘗試推導(dǎo)第一行的列分隔符。有時(shí)它會(huì)猜錯(cuò),當(dāng)然可以顯式指定分隔符。第二個(gè)可選參數(shù)是一個(gè)選項(xiàng)表:?可以重寫delim?字符串匹配模式),fieldnames(列表或逗號(hào)分隔的字符串),是否轉(zhuǎn)換no_convert?(默認(rèn)是要轉(zhuǎn)換),numfields?(列表中的列的索引)?和thousands_dot?千位在?Excel?CSV?中的分隔符是?‘.?')

一個(gè)非常強(qiáng)大的功能是在這種數(shù)據(jù)上執(zhí)行類似于?SQL?的查詢:

?--?queries?on?tabular?data

?require?'pl'

?local?d?=?data.read('xyz.txt')

?local?q?=?d:select('x,y,z?where?x?>?3?and?z?<?2?sort?by?y')

?for?x,y,z?in?q?do

?????print(x,y,z)

?end

?

請注意查詢的格式限于以下語法:

?FIELDLIST?[?'where'?CONDITION?]?[?'sort?by'?FIELD?[asc|desc]]

?

任何有效的?Lua?代碼都可以出現(xiàn)在CONDITION中;請記住它并不是SQL,您必須使用==?(此警告來自于經(jīng)驗(yàn))。

若想這樣,字段名稱必須是?Lua?的標(biāo)識(shí)符。所以read會(huì)改變字段名,這樣,所有非字母數(shù)字字符替換為下劃線。然而,?original_fieldnames字段總是包含原始字段名。

read可以很好的處理標(biāo)準(zhǔn)?CSV?文件,但是它不會(huì)嘗試成為一個(gè)全面的?CSV?分析器。加上csv=true選項(xiàng),可以處理雙引號(hào)字段,這些字段可以包含逗號(hào),尾隨逗號(hào)也是有意義的。

電子表格程并不總是處理這種數(shù)據(jù)最好的工具,這看起來可能對某些人很奇怪。下面是一個(gè)玩具?CSV?文件?;要認(rèn)識(shí)這個(gè)問題,想象類似下面的數(shù)千行和數(shù)十列:

?Department?Name,Employee?ID,Project,Hours?Booked

?sales,1231,overhead,4

?sales,1255,overhead,3

?engineering,1501,development,5

?engineering,1501,maintenance,3

?engineering,1433,maintenance,10

?

任務(wù)是減少相關(guān)的行和列的數(shù)據(jù)、?或許做一些處理行的數(shù)據(jù),并將結(jié)果寫到一個(gè)新的?CSV?文件。write_row方法使用分隔符將行寫入一個(gè)文件?;Data.select_row類似Data.select,除了它會(huì)循環(huán)訪問行,而不是字段;如果我們處理很多列,這是必要的?!

?names?=?{[1501]='don',[1433]='dilbert'}

?keepcols?=?{'Employee_ID','Hours_Booked'}

?t:write_row?(outf,{'Employee','Hours_Booked'})

?q?=?t:select_row?{

?????fields=keepcols,

?????where=function(row)?return?row[1]=='engineering'?end

?}

?for?row?in?q?do

?????row[1]?=?names[row[1]]

?????t:write_row(outf,row)

?end

?

Data.select_rowData.select可以傳遞一個(gè)表,并指定查詢?;字段表,定義條件和可選參數(shù)的sort_by函數(shù)。它不是必須的,但如果我們有更復(fù)雜的行條件?(如屬于指定的一組)。

如果不能存到hackery(不知如何翻譯)如全局變量,將不能作為一般條件查詢字符串。

在?1.0.3,您可以指定所選列的顯式轉(zhuǎn)換函數(shù)。例如,這是?Unix?日期戳一個(gè)日志文件:

?Time?Message

?1266840760?+#?EE7C0600006F0D00C00F06010302054000000308010A00002B00407B00

?1266840760?closure?data?0.000000?1972?1972?0

?1266840760?++?1266840760?EE?1

?1266840760?+#?EE7C0600006F0D00C00F06010302054000000408020A00002B00407B00

?1266840764?closure?data?0.000000?1972?1972?0

?

我們想把第一列作為實(shí)際日期對象,這樣convert可以從1顯式轉(zhuǎn)換字段。(請注意第一次我們必須顯式轉(zhuǎn)換字符串為數(shù)字)。

?Date?=?require?'pl.Date'

?

?function?date_convert?(ds)

?????return?Date(tonumber(ds))

?end

?

?d?=?data.read(f,{convert={[1]=date_convert},last_field_collect=true})

?

這給了我們一個(gè)兩列數(shù)據(jù)集,其中的第一列包含日期對象,第二列包含該行的其余部分。查詢可以很容易找出事件發(fā)生的一天:

?q?=?d:select?"Time,Message?where?Time:weekday_name()=='Sun'"

?

數(shù)據(jù)沒有來從文件,也不一定來自于實(shí)驗(yàn)室或會(huì)計(jì)部。在?Linux?上,?ps?aux為您提供在您的機(jī)器上運(yùn)行的所有進(jìn)程的完整列表。直接把ps?aux的結(jié)果送入data.read,并對它執(zhí)行有用的查詢。請注意非標(biāo)識(shí)符字符,如?%會(huì)轉(zhuǎn)化為下劃線:

?require?'pl'

?f?=?io.popen?'ps?aux'

?s?=?data.read?(f,{last_field_collect=true})

?f:close()

?print(s.fieldnames)

?print(s:column_by_name?'USER')

?qs?=?'COMMAND,_MEM?where?_MEM?>?5?and?USER=="steve"'

?for?name,mem?in?s:select(qs)?do

?????print(mem,name)

?end

?

我一直崇拜?AWK?編程語言?;使用filter中,您可以讓lua作為簡單的AWK

?--?printxy.lua

?require?'pl'

?data.filter?'x,y?where?x?>?3'

?

數(shù)據(jù)文件沒有標(biāo)題,沒有字段名稱,是常見現(xiàn)象。如果所有字段都是數(shù)字,data.read把此類文件為一個(gè)特殊的例外。由于在查詢表達(dá)式中無法使用的列名稱,您可以使用?類AWK的?索引,例如?'?$1、?$2$1?>?3'。我有一個(gè)小的可執(zhí)行腳本,在我的系統(tǒng)稱為lf這看起來像這樣:

?#!/usr/bin/env?lua

?require?'pl.data'.filter(arg[1])

?

它可用于一般的從數(shù)據(jù)中提取列的篩選器命令。(列規(guī)格可能是表達(dá)式或甚至常量)

?$?lf?'$1,$5/10'?<?test.dat

?

(與?AWK類似,請注意在此命令使用單引號(hào),這樣可以防止shell解釋列索引。如果您在?Windows?上,你必須用在雙引號(hào)引起傳遞給您的批處理文件參數(shù))。

作為教程的資源,看看test-data.lua的使用,以及其他例子的評(píng)論。

?

從readData.copy_select查詢返回的數(shù)據(jù),基本上是只是數(shù)組的行:?{{1,2},{3,4}}。所以您可以使用read處理任何類似數(shù)組的數(shù)據(jù)集,或者任何其它類似的函數(shù)處理。尤其是,在array2d函數(shù)中數(shù)據(jù)工作正常。事實(shí)上,這些函數(shù)可以作為方法?;例如array2d.flatten?,可以直接給我們一維列表:

?v?=?data.read('dat.txt'):flatten()

?

LuaMatrix期望數(shù)據(jù)像矩陣一樣正確的形狀:

?>?matrix?=?require?'matrix'

?>?m?=?matrix(data.read?'mat.txt')

?>?=?m

?1???????0.2?????0.3

?0.2?????1???????0.1

?0.1?????0.2?????1

?>?=?m^2??--?same?as?m*m

?1.07????0.46????0.62

?0.41????1.06????0.26

?0.24????0.42????1.05

?

write將寫入矩陣文件。

最后,可以使用全局變量_DEBUG打印出查詢生成并動(dòng)態(tài)編譯的實(shí)際迭代器函數(shù)。通過使用代碼生成,我們可以任優(yōu)化查詢的性能。

?>?lua?-lpl?-e?"_DEBUG=true"?-e?"data.filter?'x,y?where?x?>?4?sort?by?x'"?<?test.txt

?return?function?(t)

?????????local?i?=?0

?????????local?v

?????????local?ls?=?{}

?????????for?i,v?in?ipairs(t)?do

?????????????if?v[1]?>?4??then

?????????????????????ls[#ls+1]?=?v

?????????????end

?????????end

?????????table.sort(ls,function(v1,v2)

?????????????return?v1[1]?<?v2[1]

?????????end)

?????????local?n?=?#ls

?????????return?function()

?????????????i?=?i?+?1

?????????????v?=?ls[i]

?????????????if?i?>?n?then?return?end

?????????????return?v[1],v[2]

?????????end

?end

?

?10,20

?40,50

?

?

讀取配置文件

配置模塊提供了把幾種類型的配置文件轉(zhuǎn)換為一個(gè)?Lua?表的簡單方法??紤]的簡單示例:

?#?test.config

?#?Read?timeout?in?seconds

?read.timeout=10

?

?#?Write?timeout?in?seconds

?write.timeout=5

?

?#acceptable?ports

?ports?=?1002,1003,1004

?

可以使用config.read讀,使用pretty.write顯示結(jié)果?:

?--?readconfig.lua

?local?config?=?require?'pl.config'

?local?pretty=?require?'pl.pretty'

?

?local?t?=?config.read(arg[1])

?print(pretty.write(t))

?

lua?readconfig.lua?test.config的輸出是:

?{

???ports?=?{

?????1002,

?????1003,

?????1004

???},

???write_timeout?=?5,

???read_timeout?=?10

?}

?

config.read將產(chǎn)生所有鍵/值對,忽略?#?注釋,并確保鍵名稱是正確的?Lua?標(biāo)識(shí)符,通過非標(biāo)識(shí)符字符替換為?_。如果這些值是數(shù)字,他們將被轉(zhuǎn)換。(所以t.write_timeout的值是數(shù)字?5)。此外,由逗號(hào)分隔的任何值將同樣轉(zhuǎn)換為數(shù)組。

可以一個(gè)反斜杠續(xù)行??紤]下面這行:

?names=one,two,three,?\

?four,five,six,seven,?\

?eight,nine,ten

?

此外支持?Windows?風(fēng)格的?INI?文件。INI?文件的部分結(jié)構(gòu)自然轉(zhuǎn)換為嵌套表在?Lua?中:

?;?test.ini

?[timeouts]

?read=10?;?Read?timeout?in?seconds

?write=5?;?Write?timeout?in?seconds

?[portinfo]

?ports?=?1002,1003,1004

?

輸出為:

?{

???portinfo?=?{

?????ports?=?{

???????1002,

???????1003,

???????1004

?????}

???},

???timeouts?=?{

?????write?=?5,

?????read?=?10

???}

?}

?

你現(xiàn)在可以這樣用t.timeouts.write引用write?timeout.

最后一個(gè)例子顯示config.read?讀取逗號(hào)分隔的文件的靈活性。

?one,two,three

?10,20,30

?40,50,60

?1,2,3

?

它將生成下表:

?{

???{?"one",?"two",?"three"?},

???{?10,?20,?30?},

???{?40,?50,?60??},

???{?1,?2,?3?}

?}

?

config.read不是設(shè)計(jì)為讀取所有的?CSV?文件,但打算支持沒有鍵-值對的結(jié)構(gòu),如?'/?etc/passwd'?等一些?Unix?配置文件???。

這個(gè)函數(shù)想成為讀取配置的瑞士軍刀,它無需做出假設(shè),你也可能不喜歡他們(假設(shè))。所以有一個(gè)可選的額外參數(shù),來進(jìn)行一些控制,可能有以下字段:

?{

????variablilize?=?true,

????convert_numbers?=?tonumber,

????trim_space?=?true,

????list_delim?=?',',

????trim_quotes?=?true,

????ignore_assign?=?false,

????keysep?=?'=',

????smart?=?false,

?}

?

variablilize選項(xiàng)即第一個(gè)示例中將write.timeout轉(zhuǎn)化write_timeout?。如果convert_numbers為?true,嘗試轉(zhuǎn)換開始像數(shù)的任何字符串。您可以指定您自己的函數(shù)?(如像?'5224?kb'?的字符串轉(zhuǎn)換為數(shù)字)。

trim_space可確保有沒有開始或結(jié)尾的空白值,list_delim分割字符?(如可能?Lua?字符串模式?'%s+'.)

例如,在?Unix?中的密碼文件是冒號(hào)分隔:

?t?=?config.read('/etc/passwd',{list_delim=':'})

?

這將產(chǎn)生以下輸出在我的系統(tǒng)?(只有最后兩線所示):

?{

???...

???{

?????"user",

?????"x",

?????"1000",

?????"1000",

?????"user,,,",

?????"/home/user",

?????"/bin/bash"

???},

???{

?????"sdonovan",

?????"x",

?????"1001",

?????"1001",

?????"steve?donovan,28,,",

?????"/home/sdonovan",

?????"/bin/bash"

???}

?}

?

你可以進(jìn)入這一個(gè)更明智的格式,加上判斷哪些用戶名是索引(?tablex.pairmap函數(shù)必須返回valuekey!)

?t?=?tablex.pairmap(function(k,v)?return?v,v[1]?end,t)

?

得到:

?{?...

???sdonovan?=?{

?????"sdonovan",

?????"x",

?????"1001",

?????"1001",

?????"steve?donovan,28,,",

?????"/home/sdonovan",

?????"/bin/bash"

???}

?...

?}

?

許多常見的?Unix?配置文件可以通過調(diào)整這些參數(shù)讀取。/etc/fstab,選項(xiàng)為{list_delim=‘%s+’,ignore_assign=true}將正確分隔列。在文件里查找’KEY?VALUE’是常見的,如/etc/ssh/ssh_config;?選項(xiàng){keysep=‘?’}使config.read返回一個(gè)表,其中每個(gè)key具有一個(gè)值value。

在?Linux?中的文件procfs通常使用?':’作為分隔符

?>?t?=?config.read('/proc/meminfo',{keysep=':'})

?>?=?t.MemFree

?220140?kB

?

這一結(jié)果是一個(gè)字符串,因?yàn)閠onumber不喜歡它,但把convert_numbers定義為function(s)?return?tonumber((s:gsub('?kB$','')))?end,可以返回實(shí)際數(shù)字。(額外的括號(hào)是必要因此tonumber僅從gsub中獲取的第一個(gè)結(jié)果)。

tests/test-config.lua':

?testconfig([[

?MemTotal:????????1024748?kB

?MemFree:??????????220292?kB

?]],

?{?MemTotal?=?1024748,?MemFree?=?220292?},

?{

??keysep?=?':',

??convert_numbers?=?function(s)

?????s?=?s:gsub('?kB$','')

?????return?tonumber(s)

???end

??}

?)

?

smart選項(xiàng)可以讓config.read替你一個(gè)合理的猜測,例子為tests/test-config.lua?;旧峡梢灾苯釉谥悄苣J较绿幚磉@些常見的文件格式?(那些遵循同一模式的文件):?'?/etc/fstab?''/?proc/XXXX/status''ssh_config'?和?'pdatedb.conf'。

請注意,?config.read可以傳入類文件對象的參數(shù);如果它不是一個(gè)字符串,并支持read方法,才可以使用。例如,若要從字符串中讀取一個(gè)配置,請使用stringio.open?.

總結(jié)

以上是生活随笔為你收集整理的lua工具库penlight--06数据(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。