2015-12-07 7 views
0

Данный конфигурационный файл как таковой из Moses Machine Translation Toolkit:Разбор Moses конфигурационный файл

######################### 
### 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]} 

В настоящее время решения включать некоторые сумасшедший разворотных линий чтения из файла конфигурации, а затем довольно сложного чтение регулярных выражений, чтобы получить параметры.

Есть ли более простой или менее хакерский/подробный способ чтения файла и достижения желаемого результата словаря параметров?

Возможно ли изменить конфигурационный файл таким образом, чтобы он считывал файл конфигурации moses? Это довольно сложно, потому что в нем есть некоторые ошибочные разделы, которые фактически являются параметрами, например. [distortion-limit] и нет ключа к значению 6. В проверенном файле configparse-able это было бы distortion-limit = 6.


Примечание: Уроженец питон configparser не может обработать файл с moses.ini конфигурации. Ответы от How to read and write INI file with Python3? не будут работать.

+0

Если [это сообщение] (http://stackoverflow.com/questions/8884188/how-to-read-and-write-ini- file-with-python) не работает для вас, сообщите об этом. –

+0

@stribizhev, ответ не работает, как указано в вопросе, стандартный configparser не будет работать с ошибочным параметром без ключа. – alvas

+0

Что-то вроде '[входных факторов] \\ n0 \\ n' приведет к сбою' ConfigParser'. – alvas

ответ

1

Вот еще один короткий регулярное выражение на основе решения, которое возвращает словарь значений, похожий на ваш выход:

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 

См IDEONE demo

итоговый словарь содержание:

{'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 (регулярное выражение использует разворот техники цикла и хорошо с длинными текстами, охватывающими несколько строк).Повторное выражение с одинаковым числом, равным lazy dot, равно [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*.
  • При сборе ключей и значений последний может быть возвращен в виде списков чисел, обработанных как значения с плавающей запятой, с использованием Понимание.
+0

Технически,' r "\ [weight] [^ \ n] *' будет работать, если '[ weight] 'не является последним правилом? Так как он читает до новой строки. – alvas

+0

@alvas: К сожалению, я слишком усложнил решение, пытающееся вставить весь код в метод' successive_match'. На самом деле, решение с двумя регулярными выражениями действительно является наиболее удобный, читаемый и более эффективный. Я заменил исходный ответ на новый. Обратите внимание, что 'r" \ [weight] [^ \ n] * "' не будет выполнять работу вообще, поскольку она не будет соответствовать целое '[weight]' block. Он продолжается до символа двойной строки или конца строки. Unrolled regex является наиболее эффективным регулярным выражением для выполнения этой задачи (для регулярного выражения, конечно). Pl легко увидеть мои объяснения и спросить меня, если что-то осталось неясным. –

1

Вы можете просто сделать это.

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'])] `

+0

Не могли бы вы немного объяснить регулярное выражение? Благодаря! – alvas

+0

@alvas это регулярное выражение просто вынимает блок '[weight]', а затем анализирует его содержимое. – vks

+1

@alvas Сделал эту работу ?? – vks

1

Без регулярных выражений, вы можете сделать что-то вроде этого:

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)