Разобрать определенное количество строк из ранее проанализированного значения - PullRequest
0 голосов
/ 03 июня 2011

Я использую pyparsing, чтобы принять формат файла схемы / символа gEDA .Большинство из них прямолинейно, но я не уверен, как сопоставить количество следующих строк, указанных целочисленным полем в начальной строке.

Текстовый объект имеет формат, подобный:

(other objects)
T x y color size vis snv angle align num_lines
Text line one
Line two of the text
Finally, the 'num_lines'th line
(other objects)

с num_lines целым числом.Этот стиль используется и для нескольких других типов.

В качестве обходного пути я определяю такие строки как что-либо не , соответствующее действительному типу объекта.Технически такие объектоподобные строки допускаются в текстовых объектах

text_meta = Type("T") + coord + color + size + visibility + show_name_value \   
            + angle + alignment + num_lines + EOL                                   
text_data_line = ~obj + LineStart() + SkipTo(LineEnd()) + EOL                   
text_data = Group(OneOrMore(text_data_line)).setResultsName('text')             
text_data = text_data.setParseAction(lambda t: '\n'.join(t[0]))                 
text = text_meta + text_data

Генерация правила сопоставления на лету, например:

def genLineMatcher(n):
    return (LineStart() + Skipto(LineEnd()) + EOL)*n

находится на столе, но я не уверенкак указать правило.

Ответы [ 2 ]

0 голосов
/ 03 июня 2011

Вспомогательная функция pyparsing 'counttedArray (expr)' - почти то, что нужно.Определение синтаксического анализатора и измененная вспомогательная функция:

def numLinesList(expr, name=None):                                                                                                                                                                        
    """Helper to snarf an end-of-line integer and match 'expr' N times after.                                                                                                                        
    Almost exactly like pyparsing.countedArray.                                                                                                                                                      
    Matches patterns of the form::                                                                                                                                                                   
        ... num_lines                                                                                                                                                                                
        line one                                                                                                                                                                                     
        line two                                                                                                                                                                                     
        num_lines'th line                                                                                                                                                                            
    """                                                                                                                                                                                              
    arrayExpr = Forward()                                                                                                                                                                            
    def numLinesAction(s, l, t):                                                                                                                                                                     
        n = int(t[0])                                                                                                                                                                                
        arrayExpr << (n and Group(And([expr]*(n+1))) or Group(empty))                                                                                                                                
        return []                                                                                                                                                                                    
    matcher = Word(nums).setParseAction(numLinesAction, callDuringTry=True) \                                                                                                                        
              + arrayExpr                                                                                                                                                                            
    # remove first empty string                                                                                                                                                                      
    matcher.addParseAction(lambda t: [t[0][1:]])                                                                                                                                                     
    if name:
        matcher = matcher.setResultsName(name)                                                                                                                                                           
    return matcher

text_meta = Type("T") + coord + color + size + visibility + show_name_value \   
        + angle + alignment
text_data_line = SkipTo(LineEnd()) + EOL
text_data = numLinesList(text_data_line, 'text')
text = text_meta + text_data

Для входного фрагмента:

...
T 41600 47800 9 10 1 0 0 0 2                                                                                                                                                                         
This is line 1                                                                                                                                                                                       
line 2 is here...                                                                                                                                                                                    
T 41600 47000 9 10 1 0 0 0 2                                                                                                                                                                         
Another first line                                                                                                                                                                                   
second line foo

Это выводит:

['T', 41600, 47800, '9', 10, True, '0', 0, 0, ['This is line 1', 'line 2 is here...']]
['T', 41600, 47000, '9', 10, True, '0', 0, 0, ['Another first line', 'second line foo']]
0 голосов
/ 03 июня 2011

Создание правила совпадения на лету ...

Вы на правильном пути. Способ создания правила на лету состоит в том, чтобы определить выражение переменной длины как Forward (), а затем в действии синтаксического анализа вставить фактическое правило при разборе поля count.

К счастью, в pyparsing это уже реализовано в вспомогательном методе countedArray. Если вы измените свое выражение на:

text_meta = (Type("T") + coord + color + size + visibility + show_name_value +
               angle + alignment + countedArray(EOL + restOfLine)("lines"))

Я думаю, что это будет делать то, что вы хотите. Затем вы можете получить массив строк, используя имя результата "lines".

...