[英]Parsing a Moses config file
從Moses Machine Translation Toolkit中獲得這樣的配置文件:
#########################
### MOSES CONFIG FILE ###
#########################
# input factors
[input-factors]
0
# mapping steps
[mapping]
0 T 0
[distortion-limit]
6
# feature functions
[feature]
UnknownWordPenalty
WordPenalty
PhrasePenalty
PhraseDictionaryMemory name=TranslationModel0 num-features=4 path=/home/gillin/jojomert/phrase-jojo/work.src-ref/training/model/phrase-table.gz input-factor=0 output-factor=0
LexicalReordering name=LexicalReordering0 num-features=6 type=wbe-msd-bidirectional-fe-allff input-factor=0 output-factor=0 path=/home/gillin/jojomert/phrase-jojo/work.src-ref/training/model/reordering-table.wbe-msd-bidirectional-fe.gz
Distortion
KENLM lazyken=0 name=LM0 factor=0 path=/home/gillin/jojomert/ru.kenlm order=5
# dense weights for feature functions
[weight]
UnknownWordPenalty0= 1
WordPenalty0= -1
PhrasePenalty0= 0.2
TranslationModel0= 0.2 0.2 0.2 0.2
LexicalReordering0= 0.3 0.3 0.3 0.3 0.3 0.3
Distortion0= 0.3
LM0= 0.5
我需要從[weights]
部分讀取參數:
UnknownWordPenalty0= 1
WordPenalty0= -1
PhrasePenalty0= 0.2
TranslationModel0= 0.2 0.2 0.2 0.2
LexicalReordering0= 0.3 0.3 0.3 0.3 0.3 0.3
Distortion0= 0.3
LM0= 0.5
我一直在這樣做:
def read_params_from_moses_ini(mosesinifile):
parameters_string = ""
for line in reversed(open(mosesinifile, 'r').readlines()):
if line.startswith('[weight]'):
return parameters_string
else:
parameters_string+=line.strip() + ' '
獲得此輸出:
LM0= 0.5 Distortion0= 0.3 LexicalReordering0= 0.3 0.3 0.3 0.3 0.3 0.3 TranslationModel0= 0.2 0.2 0.2 0.2 PhrasePenalty0= 0.2 WordPenalty0= -1 UnknownWordPenalty0= 1
然后使用解析輸出
moses_param_pattern = re.compile(r'''([^\s=]+)=\s*((?:[^\s=]+(?:\s|$))*)''')
def parse_parameters(parameters_string):
return dict((k, list(map(float, v.split())))
for k, v in moses_param_pattern.findall(parameters_string))
mosesinifile = 'mertfiles/moses.ini'
print (parse_parameters(read_params_from_moses_ini(mosesinifile)))
要得到:
{'UnknownWordPenalty0': [1.0], 'PhrasePenalty0': [0.2], 'WordPenalty0': [-1.0], 'Distortion0': [0.3], 'LexicalReordering0': [0.3, 0.3, 0.3, 0.3, 0.3, 0.3], 'TranslationModel0': [0.2, 0.2, 0.2, 0.2], 'LM0': [0.5]}
當前的解決方案包括從配置文件中讀取一些瘋狂的反轉行,然后讀取相當復雜的正則表達式以獲取參數。
有沒有更簡單或更簡潔的方法來讀取文件並實現所需的參數字典輸出?
是否可以更改configparser以使其讀取moses配置文件? 這很困難,因為它實際上有一些錯誤的部分是參數,例如[distortion-limit]
並且沒有值6
鍵。 在經過驗證的可配置文件中,該文件將為distortion-limit = 6
。
注意:本機python configparser
無法處理moses.ini
配置文件。 如何使用Python3讀取和寫入INI文件的答案? 不管用。
您可以簡單地做到這一點。
x="""#########################
### MOSES CONFIG FILE ###
#########################
# input factors
[input-factors]
0
# mapping steps
[mapping]
0 T 0
[distortion-limit]
6
# feature functions
[feature]
UnknownWordPenalty
WordPenalty
PhrasePenalty
PhraseDictionaryMemory name=TranslationModel0 num-features=4 path=/home /gillin/jojomert/phrase-jojo/work.src-ref/training/model/phrase-table.gz input-factor=0 output-factor=0
LexicalReordering name=LexicalReordering0 num-features=6 type=wbe-msd-bidirectional-fe-allff input-factor=0 output-factor=0 path=/home/gillin/jojomert/phrase-jojo/work.src-ref/training/model/reordering-table.wbe-msd-bidirectional-fe.gz
Distortion
KENLM lazyken=0 name=LM0 factor=0 path=/home/gillin/jojomert/ru.kenlm order=5
# dense weights for feature functions
[weight]
UnknownWordPenalty0= 1
WordPenalty0= -1
PhrasePenalty0= 0.2
TranslationModel0= 0.2 0.2 0.2 0.2
LexicalReordering0= 0.3 0.3 0.3 0.3 0.3 0.3
Distortion0= 0.3
LM0= 0.5"""
print [(i,j.split()) for i,j in re.findall(r"([^\s=]+)=\s*([\d.\s]+(?<!\s))",re.findall(r"\[weight\]([\s\S]*?)(?:\n\[[^\]]*\]|$)",x)[0])]
輸出: [('UnknownWordPenalty0', ['1']), ('PhrasePenalty0', ['0.2']), ('TranslationModel0', ['0.2', '0.2', '0.2', '0.2']), ('LexicalReordering0', ['0.3', '0.3', '0.3', '0.3', '0.3', '0.3']), ('Distortion0', ['0.3']), ('LM0', ['0.5'])]
`
這是另一個基於正則表達式的簡短解決方案,該解決方案返回類似於您的輸出的值的字典:
import re
from collections import defaultdict
dct = {}
str="MOSES_INI_FILE_CONTENTS"
#get [weight] section
match_weight = re.search(r"\[weight][^\n]*(?:\n(?!$|\n)[^\n]*)*", str) # Regex is identical to "(?s)\[weight].*?(?:$|\n\n)"
if match_weight:
weight = match_weight.group() # get the [weight] text
dct = dict([(x[0], [float(x) for x in x[1].split(" ")]) for x in re.findall(r"(\w+)\s*=\s*(.*)\s*", weight)])
print dct
產生的字典內容:
{'UnknownWordPenalty0': [1.0], 'LexicalReordering0': [0.3, 0.3, 0.3, 0.3, 0.3, 0.3], 'LM0': [0.5], 'PhrasePenalty0': [0.2], 'TranslationModel0': [0.2, 0.2, 0.2, 0.2], 'Distortion0': [0.3], 'WordPenalty0': [-1.0]}
邏輯:
[weight]
塊。 它可以用做r"\\[weight][^\\n]*(?:\\n(?!$|\\n)[^\\n]*)*"
匹配正則表達式[weight]
從字面上來看,那么它匹配每個字符多次,直到出現雙\\n
符號為止(正則表達式使用展開循環技術,並且對於跨越幾行的較長文本來說是很好的選擇)。 相同的基於懶點的正則表達式為[ r"(?s)\\[weight].*?(?:$|\\n\\n)"
],但效率不高(第一個正則表達式為62個步驟,第528個為第二個正則表達式可在當前MOSES.ini文件中找到匹配項),但絕對更易讀。 re.findall(r"(\\w+)\\s*=\\s*(.*)\\s*", weight)
方法來收集所有鍵值對。 使用的正則表達式是簡單的(\\w+)\\s*=\\s*(.*)\\s*
匹配並捕獲到第1組中的一個或多個字母數字符號( (\\w+)
),后跟任意數量的空格=
,再次使用任意數量的空格( \\s*=\\s*
),然后將除換行符之外的所有符號匹配並捕獲到組2中,直到字符串末尾。 尾隨空格的尾隨換行符用最后的\\s*
修剪。 沒有正則表達式,您可以執行以下操作:
flag = False
result = dict()
with open('moses.ini', 'rb') as fh:
for line in fh:
if flag:
parts = line.rstrip().split('= ')
if len(parts) == 2:
result[parts[0]] = [float(x) for x in parts[1].split()]
else:
break
elif line.startswith('[weight]'):
flag = True
print(result)
在循環中逐行讀取文件,當達到[weight]
時,將標志設置為True
並為接下來的所有行提取鍵/值,直到空白行或文件末尾。
這樣,僅將當前行加載到內存中,並且一旦到達[weight]
塊的末尾,程序就會停止讀取文件。
使用itertools
的另一種方式:
from itertools import *
result = dict()
with open('moses.ini', 'rb') as fh:
a = dropwhile(lambda x: not(x.startswith('[weight]')), fh)
a.next()
for k,v in takewhile(lambda x: len(x)==2, [y.rstrip().split('= ') for y in a]):
result[k] = [float(x) for x in v.split()]
print(result)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.