Как я могу разобрать это без регулярного выражения?

#regex #parsing #text #sabre

#регулярное выражение #синтаксический анализ #текст #sabre

Вопрос:

Мой друг сказал, что если используемое мной регулярное выражение слишком длинное, то, вероятно, это неподходящий инструмент для работы. Есть какие-нибудь мысли о лучшем способе разбора этого текста? У меня есть регулярное выражение, которое возвращает все в массив, который я могу легко просто вырезать, но если есть другой более простой способ, я бы действительно хотел его увидеть.

Вот как это выглядит:

  2 AB 123A 01JAN M ABCDEF AA1   100A  200A  02JAN T /ABCD /E    
  

Вот разбивка этого:

  • 2 это номер строки, они варьируются от 1 вплоть до 99 . Если вы не видите из-за форматирования, перед числами, меньшими 10, есть символ пробела.

    Пробел может быть заменен, а может и не быть, символом *

  • AB является важной единицей данных (UOD).

    AB может добавляться /CD , что является еще одним важным UOD.

  • 123 это важный UOD. Оно может варьироваться от 1 (с добавлением 4 пробелов) до 99999 .

  • A это важный UOD.

  • 01JAN это комбинация день / месяц, мне нужно извлечь оба UOD.

  • M это сокращенная форма названия дня. Это может быть число между 1 и 7 .

  • ABC это важный UOD.

  • DEF это важный UOD.

    Пробел после DEF может быть *

  • AA1 может содержать ноль символов, или это может быть 5. Это неважно.

  • 100A это временная метка, но может быть в формате 1300 . A Может быть N , когда время 1200 или P для раз в PM.

  • Затем мы видим другую временную метку.

  • Следующей части даты может не быть, например, это допустимо:

     93*DE/QQ51234 30APR J QWERTY*QQ0   1250   0520 /ABCD*ASDFAS /E             
      
  • Данные, в которых /ABCD*ASDFAS /E отображаются, не имеют отношения к приложению, но именно здесь может появиться вторая отметка даты. Косая черта спереди может быть чем-то другим (например, буквой).

Примечание:
Это не разделено пробелом, некоторые части тела переходят в другие. Позиция символа является точной только для первых двух или трех элементов в списке

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

Комментарии:

1. en.wikipedia.org/wiki/Finite-state_machine

2. Это не домашнее задание, это очистка экрана от устаревшей системы. scribd.com/doc/24980105/Mysabre-Manual (см. стр. 35)

3. Регулярное выражение кажется мне отличной идеей.

4. @Ignacio Vazquez-Abrams Не могли бы вы добавить краткое объяснение? Я не смог выяснить, как применить FSM к этому из статьи в Вики, особенно потому, что я никогда ими не пользовался и всегда думал, что их применение находится в другом месте, например, для мониторинга истории объекта.

Ответ №1:

Это идеальная задача для регулярных выражений. Текст не содержит вложенности, и элементы, которые вы сопоставляете, довольно просты по отдельности.

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

 $regex = '@
    # 2 is the line number, these range from 1 all the way to 99.
    # There is a space character prepending numbers less than 10.
    # The space may or may not be replaced by an *.
    [ *]d|dd
    s

    # AB is an important unit of data (UOD).
    # AB may be prepended by /CD which is another important UOD.
    (/CD)?AB
    s

    # 123 is an important UOD. It can range from 1 (prepended by 4 spaces)
    # to 99999.
    s{4}d{1}|s{3}d{2}|s{2}d{3}|s{1}d{4}|d{5}
@x';
  

И так далее.

Комментарии:

1. Вау, я не знал о комментировании внутри регулярного выражения, это на самом деле действительно круто. Спасибо!

Ответ №2:

Регулярное выражение кажется подходящим для этого приложения, но для простоты и удобочитаемости вы можете разбить его на несколько регулярных выражений (по одному для каждого поля), чтобы людям было легче отслеживать, какая часть регулярного выражения соответствует какой переменной.

Ответ №3:

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

Комментарии:

1. Вы имеете в виду, что писать построчную серию сложных операторов if и проверок подстрок проще, чем регулярное выражение?

2. Если регулярное выражение сложное, да. Каждый отдельный оператор не будет сложным.

Ответ №4:

Просто напишите пользовательский анализатор, который обрабатывает это построчно. Кажется, что все находится в фиксированной позиции, а не через пробел / запятую, поэтому просто используйте их в качестве индексов в том, что вам нужно:

 line_number = int(line_text[0:1])
ab_unit = line_text[3:4]
...
  

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

Комментарии:

1. Это не разделено пробелом, некоторые части тела переходят в другие. Позиция символа является точной только для первых двух или трех элементов в списке. Кроме того, некоторые пробелы могут превратиться в *.