Подтвердить что ты не робот

Разбор строк в Python: используйте RE или нет?

Я программист Perl, который пытается изучить Python, выполнив некоторую работу, которую я сделал раньше, и преобразовал ее в Python. Это НЕ перевод строки за строкой. Я хочу изучить технику Python для выполнения этого типа задач.

Я разбираю файл INI Windows. Названия разделов имеют формат:

[<type> <description>]

<type> - одно слово и не чувствителен к регистру. <description> может быть несколькими словами.

После раздела есть множество параметров и значений. Они представлены в виде:

 <parameter> = <value>

Параметры не имеют пробелов и могут содержать только символы подчеркивания, буквы и цифры (без учета регистра). Таким образом, первый = является делителем между параметром и значением. Может существовать пробел, разделяющий параметр и значение вокруг знака равенства. В начале или конце строки может быть дополнительное свободное пространство.

В Perl я использовал регулярные выражения для синтаксического анализа:

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";
    }

}

Проблема в том, что я был поврежден Perl, поэтому я считаю, что самый простой способ сделать что-то - использовать регулярное выражение. Вот код, который у меня есть до сих пор...

 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. Что такое способ Python для решения этой проблемы?
  • В конце концов, мой алгоритм очень похож на мой алгоритм Perl, и это, похоже, говорит, что я позволяю думать о Perl. Как мой код должен быть структурирован в Python?

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

Мой вопрос:

  • Должен ли я использовать регулярные выражения? Или есть другой и лучший способ справиться с этим?
  • Правильно ли моя логика кодирования? Как я должен думать о разборе этого файла?
4b9b3361

Ответ 1

Пока я не думаю, что это ваше намерение, формат файла кажется очень похожим на Python встроенный ConfigParser модуль. Иногда самый "питонический" путь уже предусмотрен для вас. (

В более прямом ответе на ваш вопрос: регулярные выражения могут быть хорошим способом сделать это. В противном случае вы можете попробовать более простые (и менее надежные)

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

Это вызовет ошибку, если строка содержит не более одного символа '='. Вы можете сначала протестировать его с помощью '=' in line.

также:

line.find("[") == 1

вероятно, лучше заменить на

line.startswith("[")

Надеюсь, что немного helpls (:

Ответ 2

Python включает в себя ini parsing library. Если вы хотите создать библиотеку для анализа ini файлов, то вы смотрите на фактический синтаксический анализатор. Regex не будет его обрезать, используйте PLY или зацепите синтаксический анализатор flex/bison C. Также доступны дополнительные ресурсы для анализа python.

Лексеры обрабатывают все потребление текста и древовидную структуру для вас, поскольку это механическая задача, подверженная ошибкам программиста. И.Е. этот раздел:

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";
    }

}

Создается с помощью lexer, вам просто нужно определить правильное Regex. Парсер вытаскивает маркеры из лексера и определяет, соответствуют ли они допустимым шаблонам токенов. То есть:

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

Определите эти жетоны, а затем как им разрешено соответствовать. Все остальное просто объединяется. Для тех из вас, кто думает, что вы можете сделать лучшую работу с быстрым циклом и некоторым регулярным выражением, я предлагаю вам читать Lex и Yacc, 2nd Ed.

Для примера синтаксического анализатора я написал с PLY, перейти сюда. Он анализирует файл "jetLetter", который является просто диалектом groff/troff.

Ответ 3

Да, в любом случае используйте регулярные выражения. Синтаксис строк .INI файла, который вы пытаетесь разобрать, математически соответствует характеристикам грамматики Chomsky Type 3 (регулярная), которая является точно таким же, как обычные регулярные выражения, для анализа.

Регулярные выражения, которые вам нужны (с головы до ног, непроверенные), вроде:

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

и

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

Используйте re.search, а в возвращаемом сопоставить объекты, вы можете извлечь группы, соответствующие группам в скобках в выражениях.