2012-02-08 2 views
12

필자는 Perl 프로그래머로서 전에 해본 작업을 파이썬으로 변환하여 파이썬을 배우려고 시도하고 있습니다. 이것은 이 아니고 라인별로 번역됩니다. 이 유형의 작업을 수행하려면 Python Technique을 배우고 싶습니다.파이썬에서 행 파싱하기 : RE 또는 NOT을 사용 하시겠습니까?

Windows INI 파일을 구문 분석하고 있습니다. 섹션 이름은 형식으로되어 있습니다 :

[<type> <description>] 

<type>는 하나의 단어 필드이며 대소 문자를 구분하지 않습니다. <description>은 여러 단어 일 수 있습니다.

섹션 뒤에는 많은 매개 변수와 값이 있습니다. 이들은 다음과 같은 형식입니다 :

<parameter> = <value> 

매개 변수에는 공백이없고 밑줄, 문자 및 숫자 만 사용할 수 있습니다 (대소 문자 구분). 따라서 첫 번째 =은 매개 변수와 값 사이의 구분자입니다. 등호 주위에 매개 변수와 값을 구분하는 공백이있을 수 있습니다. 행의 처음 또는 끝에 여분의 공백이있을 수 있습니다.

while (my $line = <CONTROL_FILE>) { 
    chomp($line); 
    next if ($line =~ /^\s*[#;']/);  #Comments start with "#", ";", or "'" 
    next if ($line =~ /^\s*$/);   #Ignore blank lines 

    if ($line =~ /^\s*\[\s*(\w+)\s+(.*)/) { #Section 
     say "This is a '$1' section called '$2'"; 
    } 
    elsif ($line =~ /^\s*(\w+)\s*=\s*(.*)/) { #Parameter 
     say "Parameter is '$1' with a value of '$2'"; 
    } 
    else {  #Not Comment, Section, or Parameter 
     say "Invalid line"; 
    } 

} 

문제는 내가 펄에 의해 손상 봤는데, 그래서 내가 뭔가를 할 수있는 가장 쉬운 방법은 정규 표현식을 사용하는 것입니다 생각 :

펄, 나는 파싱을위한 정규 표현식을 사용했다. 정규 표현식 그냥 사용 부르고 것으로 보인다

  • 가 두 곳이 있습니다 : 여기 여기 나를 자극하는 몇 가지가 있습니다

    for line in file_handle: 
        line = line.strip 
    
        # Comment lines and blank lines 
        if line.find("#") == 1 \ 
          or line.find(";") == 1 \ 
          or line.whitespace: 
         continue 
    
        # Found a Section Heading 
        if line.find("[") == 1: 
         print "I want to use a regular expression here" 
         print "to split the section up into two pieces" 
        elif line.find("=") != -1: 
         print "I want to use a regular expression here" 
         print "to split the parameter into key and value" 
        else 
         print "Invalid Line" 
    

    내가 지금까지 가지고있는 코드는 ...입니다. 이 분할을 수행하는 Python의 방식은 무엇입니까?

  • 문자열의 양쪽에 공백을 제거하고 문자열을 다시 작성해야합니다. 그렇게하면 여러 번 스트리핑을 할 필요가 없습니다. 그러나 필자가 이해하는 문자열은 Python에서 매우 비효율적 인 작업으로 다시 작성합니다. 이 문제를 처리 할 파이썬 방법은 무엇입니까?
  • 결국, 내 알고리즘은 내 Perl 알고리즘과 매우 흡사하게 보입니다. 내 Perl을 생각하게 만드는 것 같습니다. 코드가 파이썬으로 어떻게 구성되어야합니까?

나는 다양한 온라인 튜토리얼을 통해 구문을 이해하는 데 도움이되었지만 언어 자체를 다루는 방법은별로 아니었다. 특히 다른 언어를 생각하는 경향이있는 사람 언어.

내 질문 :

  • 내가 정규식을 사용 하는가? 아니면 이것을 처리 할 수있는 또 다른 방법이 있습니까?
  • 코딩 논리가 맞습니까? 이 파일의 구문 분석을 어떻게 생각해야합니까?
+3

['ConfigParser'] (http://docs.python.org/library/configparser.html) 모듈을 확인하십시오. –

+0

Perl에서 당신은'부패하지 않습니다.'당신에게 축복을드립니다. – joaquin

+0

@SvenMarnach - 당신의 제안에 감사드립니다. 그러나 나는 이미 그것을 보았습니다. 문제는 ConfigParser가 출력물을 사전에 집어 넣고이 특정 응용 프로그램에서 실제로 중요한 사전 섹션의 순서를 보장 할 수 없다는 것입니다. 필자는 Perl에서 [Config :: Ini] (http://search.cpan.org/~rjbs/Config-INI-0.019/lib/Config/INI.pm) 모듈과 동일한 문제가있었습니다. 게다가, 이것은 나에게 파이썬의 기능을 실제로 배울 수있는 기회를 제공한다. –

답변

4

이것이 사용자의 의도라고 생각하지 않지만 파일 형식은 파이썬의 내장 ConfigParser 모듈과 매우 유사합니다. 때로는 가장 "Pythonic"방식이 이미 제공됩니다. (:

질문에 대한 직접적인 대답에

:. 정규 표현식이 작업을 수행 할 수있는 좋은 방법이 될 수 있습니다 그렇지 않으면, 당신은) 기본적인 (덜 강력한

(parameter, value) = line.split('=') 

이 오류를 슬로우 시도 할 수 . 선이 없거나 하나 이상의 '='문자가 포함 된 경우 '=' in line로 먼저 테스트 할 수 없다 또한

:.

line.find("[") == 1 

아마 더 (조금 helpls

line.startswith("[") 

희망으로 대체 : 꼭

+0

감사합니다. 실제로 모듈을 보았습니다.하지만 유감스럽게도 결과는 사전에 저장되므로 섹션을 읽은 순서를 잃어 버릴 수 있습니다. 섹션의 순서는 매우 중요합니다. Perl에서 [Config :: Ini] (http://search.cpan.org/~rjbs/Config-INI-0.019/lib/Config/INI.pm) 모듈과 동일한 문제가 발생했습니다. 게다가, 아이디어는 언어를 배우는 것입니다. 'startswith' 메쏘드에 대한 포인터를 보내 주셔서 감사합니다. –

+0

@ David 환영합니다. 나는 내장 방법이 어쨌든 똑같지는 않을 것이라고 생각했다. :) – tjvr

+0

'='기호가 2 개 이상 나오지 않도록하려면'line.split ('=', 1)'을 사용하십시오. '=', '='('=', 1) + [ '']) [: 2]'. LHS 튜플 주위에()를 넣지 마십시오. 불필요한 혼란입니다. 또한'line.strip()'을 사용하여'line.strip'을 호출해야합니다 - 당신이 가지고있는 코드는 바운드 메소드 스트립으로 줄을 바꿀 것입니다. – PaulMcG

5

파이썬에는 ini parsing library이 포함됩니다. ini 파일을 파싱하기 위해 라이브러리를 빌드하려는 경우 실제 파서가 있습니다. Regex는 이것을 자르지 않고 PLY을 사용하거나 flex/bison C 파서를 사용합니다.Additional python parsing resources are available as well.

Lexers는 프로그래머 오류가 발생하기 쉬운 기계적 작업이므로 모든 텍스트 소비 및 트리 구성을 처리합니다. I.E. 이 섹션은

while (my $line = <CONTROL_FILE>) { 
    chomp($line); 
    next if ($line =~ /^\s*[#;']/);  #Comments start with "#", ";", or "'" 
    next if ($line =~ /^\s*$/);   #Ignore blank lines 

    if ($line =~ /^\s*\[\s*(\w+)\s+(.*)/) { #Section 
     say "This is a '$1' section called '$2'"; 
    } 
    elsif ($line =~ /^\s*(\w+)\s*=\s*(.*)/) { #Parameter 
     say "Parameter is '$1' with a value of '$2'"; 
    } 
    else {  #Not Comment, Section, or Parameter 
     say "Invalid line"; 
    } 

} 

으로 작성되었습니다. 올바른 Regex를 정의하면됩니다. 파서는 렉서 (lexer)에서 토큰을 가져 와서 허용 토큰 패턴에 맞는지 판단합니다. 즉 :

[<type> <description>] 
<parameter> = <value> 

해당 토큰을 정의한 다음 허용되는 방법을 정의하십시오. 다른 모든 것들은 그저 함께 있습니다. 자네가 빠른 for 루프와 정규 표현식으로 더 나은 일을 할 수 있다고 생각하는 사람들을 위해 나는 읽는 것을 추천한다. Lex & Yacc, 2nd Ed.

예를 들어 나는 PLY, go here으로 썼다. groff/troff의 방언 인 "jetLetter"파일을 구문 분석합니다.

+0

+1 많은 일을하는 '파이썬'방식이 라이브러리의 강력한 빌드를 어떻게 알고 있는지 보여주기 위해 +1. –

+0

최근에이 사이트에서 배웠던 경량의 멋진 파싱 라이브러리 인 [lepl] (http://www.acooke.org/lepl/)에 대한 링크를 넣으려고합니다. –

0

예는,이 경우 정규 표현식을 사용합니다. 구문 분석하려는 .INI 파일 행의 구문은 Chomsky Type 3 (정규) 문법의 특성 내에서 수학적으로 적합합니다. 정규식은 구문 분석하도록 설계된 것과 정확히 같습니다. 당신이 필요로하는

정규 표현식은 같은 (테스트되지 않은, 내 머리 위로 떨어져)은 다음과 같습니다

r"^\[\s*(\w)\s+(.*)\]$" 

r"^(\w)\s*\=\s*(.*)$" 

사용 re.search 및 반환 Match objects, 당신은 추출 할 수 있습니다 그룹은 표현식에서 괄호로 묶인 그룹에 해당합니다.

관련 문제