#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. Это не разделено пробелом, некоторые части тела переходят в другие. Позиция символа является точной только для первых двух или трех элементов в списке. Кроме того, некоторые пробелы могут превратиться в *.