Как уже упоминалось, вам нужно некоторую структуру в вашем регулярном выражении. Подтверждая ваш код, я сделал пару предположений
- Вы не хотите просто распечатать его в формате с разделителями-вкладками
- Единственная причина для переменной
$x
состоит в том, что вы печатаете только одну строку.
(хотя last
в конце цикла работало бы просто отлично.).
Приняв эти вещи, я решил, что, отвечая на ваш вопрос, я бы:
- Покажите, как сделать хороший модифицируемый регулярное выражение.
- Код очень простых «семантических действий», которые хранят данные и позволяют вам
используйте его как угодно.
Кроме того, следует отметить, что я изменил ввод в секцию __DATA__
и
вывод ограничен STDERR - с помощью Smart::Comment
комментариев,
что мне нужно проверить мои структуры.
Сначала преамбула кода.
use strict; # always in development!
use warnings; # always in development!
use English qw<$LIST_SEPARATOR>; # It's just helpful.
#use re 'debug';
#use Smart::Comments
Обратите внимание на закомментированный use re
.... Если вы действительно хотите увидеть, как регулярный
выражение будет проанализировано, оно выдаст много информации, которую вы, вероятно,
не хочу видеть (но могу пробиться - с небольшим знанием о
Тем не менее, регулярный синтаксический анализ. Это закомментировано, потому что это не новичок
дружественный, и будет монополизировать вашу продукцию. (Подробнее об этом см. re .)
Также закомментирована строка use Smart::Comments
. Я рекомендую это, но вы
можно получить, используя Data::Dumper
и print Dumper( \%hash )
строки. (См. Smart::Comments
.)
Указание выражения
Но на регулярное выражение. Я использовал взорванную форму регулярного выражения, так что части
все объясняется (см. perlre ). Нам нужен один буквенно-цифровой символ ИЛИ строка в кавычках
(с разрешенными побегами).
Мы также использовали список имен модификаторов, чтобы «язык» мог развиваться.
Следующее регулярное выражение, которое мы создаем в блоке do, или, как мне нравится называть это, «локализация
блок ", так что я могу локализовать $LIST_SEPARATOR
(он же $"
), чтобы быть регулярным выражением
символ чередования. ( '|'). Таким образом, когда я включаю список для интерполяции,
оно интерполируется как чередование.
Я дам вам время взглянуть на второе регулярное выражение, прежде чем говорить об этом.
# Modifiable list of modifiers
my @mod_names = qw<constant fixup private>;
# Break out the more complex chunks into separate expressions
my $arg2_regex
= qr{ \p{IsAlnum} # accept a single alphanumeric character
| # OR
" # Starts with a double quote
(?> # -> We just want to group, not capture
# the '?> controls back tracing
[^\\"\P{IsPrint}]+ # any print character as long as it is not
# a backslash or a double quote
| \\" # but we will accept a backslash followed by
# a double quote
| (\\\\)+ # OR any amount of doubled backslashes
)* # any number of these
"
}msx;
my $line_RE
= do { local $LIST_SEPARATOR = '|';
qr{ \A # the beginning
\s* # however much whitespace you need
# A sequence of modifier names followed by space
((?: (?: @mod_names ) \s+ )*)
( \p{IsAlnum}+ ) # at least one alphanumeric character
\s* # any amount of whitespace
= # an equals sign
\s* # any amount of whitespace
< # open angle bracket
(\p{IsAlnum}+) # Alphanumeric identifier
\s+ # required whitespace
( $arg2_regex ) # previously specified arg #2 expression
[^>]*?
> # close angle bracket
}msx
;
};
Регулярное выражение просто говорит, что мы хотим, чтобы любое количество распознанных "модификаторов" отделялось
пробелом, сопровождаемым буквенно-цифровым идентификатором (я не уверен, почему вы не
хочу подчеркнуть; Я не включаю их, в любом случае.)
За ним следует любое количество пробелов и знак равенства. Так как наборы
буквенно-цифровых символов, пробелы и знак равенства не пересекаются,
нет причин требовать пробелы. На другой стороне знака равенства,
значение ограничено угловыми скобками, поэтому я не вижу смысла для требовать
пробелы на этой стороне либо. До равенства все, что вы позволили
буквенно-цифровые символы и пробелы, а с другой стороны, все это должно быть под углом
скобки. Требуемый пробел ничего не дает, а не требует больше
отказоустойчивой. Игнорируйте все это и замените *
s на +
, если вы ожидаете
выход машины.
На другой стороне знака равенства нам нужна пара угловых скобок. Пара
состоит из буквенно-цифрового аргумента, причем вторым аргументом является ЛИБО
один буквенно-цифровой символ (в зависимости от вашей спецификации) ИЛИ строка, которая может содержать
экранированные экранирования или кавычки и даже конечная угловая скобка - до тех пор, пока строка
не заканчивается.
Хранение данных
После того, как спецификация сделана, вот только одна из вещей, которые вы можете сделать
с этим. Потому что я не знаю, что ты хотел с этим сделать, кроме как распечатать
Out - что я собираюсь предположить, не вся цель сценария.
### $line_RE
my %fixup_map;
while ( my $line = <DATA> ) {
### $line
my ( $mod_text, $identifier, $first_arg, $second_arg )
= ( $line =~ /$line_RE/ )
;
die 'Did not parse!' unless $identifier;
$fixup_map{$identifier}
= { modifiers_for => { map { $_ => 1 } split /\s+/, $mod_text }
, first_arg => $first_arg
, second_arg => $second_arg
};
### $fixup_map{$identifier} : $fixup_map{$identifier}
}
__DATA__
constant fixup ConfigAlarms = <U1 0>
constant fixup ConfigAlarms2 = <U1 2>
constant fixup private AlarmFileName = <A "C:\\TMP\\ALARM.LOG">
В конце вы можете увидеть раздел DATA
, когда вы находитесь на начальной стадии как
вы, кажется, здесь, наиболее удобно обойтись без логики ввода-вывода и использовать
встроенная ручка DATA
как у меня здесь.
Я собираю модификаторы в хэш, чтобы мои семантические действия могли быть
#...
my $data = $fixup_map{$id};
#...
if ( $data->{modifiers_for}{public} ) {
#...
}
Мыльница
Однако главная проблема в том, что у вас нет плана. Для второго «аргумента» в угловых скобках у вас есть регулярное выражение, которое указывает только один буквенно-цифровой символ, но вы хотите расширить его, чтобы разрешить экранированные строки. Я должен ожидать, что вы реализуете небольшое подмножество и постепенно хотите расширять его, делая другие вещи. Если вы пренебрегаете хорошим дизайном с самого начала, то реализация полнофункционального «парсера» станет головной болью.
Возможно, вы захотите реализовать многострочные значения в какой-то момент. Если вы не понимаете, как перейти от единственного алфавитно-цифрового аргумента к аргументу, заключенному в кавычки, то построчный метод и корректировки регулярного выражения уменьшают этот пробел в сложности.
Поэтому я советую вам использовать код здесь только в качестве директивы для увеличения сложности. Я отвечаю на вопрос и указываю направление, а не проектирую или кодирую проект, поэтому мой код регулярного выражения не так расширяем, как это должно быть.
Если бы анализ был достаточно сложным, я бы указал минимальную грамматику предпросмотра для Parse::RecDescent
и придерживался кодирования семантических действий. Это еще одна рекомендация.