Сейчас я изучаю регулярные выражения, но мне это кажется немного сложным. Я читаю какой-то код на TCL, но что он хочет сопоставить?
regexp ".* (\[\\d]\{3\}:\[\\d]\{3\}:\[\\d]\{3\}.\[\\d]\{5\}).\[^\\n]" $input
Сейчас я изучаю регулярные выражения, но мне это кажется немного сложным. Я читаю какой-то код на TCL, но что он хочет сопоставить?
regexp ".* (\[\\d]\{3\}:\[\\d]\{3\}:\[\\d]\{3\}.\[\\d]\{5\}).\[^\\n]" $input
Если вы не экранируете символы, вы получите следующее:
.* ([\d]{3}:[\d]{3}:[\d]{3}.[\d]{5}).[^\n]
Термин [\d]{x}
будет соответствовать x
количеству последовательных цифр. Поэтому часть в круглых скобках будет соответствовать чему-то вроде ###:###:###?#####
(где #
может быть любой цифрой, а ?
может быть любым символом). Сами круглые скобки не совпадают, они просто используются для указания того, какую часть ввода «захватить» и вернуть вызывающей стороне. За этой последовательностью следует одна точка .
, которая соответствует одному символу (который может быть любым). Завершающий [^\n]
будет соответствовать одиночному символу, который является чем угодно, кроме новой строки (^
в начале выражения в квадратных скобках инвертирует совпадение). Термин .*
в самом начале соответствует последовательности символов любой длины (даже нулевой), за которой следует пробел.
Принимая все это во внимание, получается, что это регулярное выражение извлекает серию цифр из середины строки. Учитывая формат чисел, он может искать метку времени в формате hours:minutes:seconds.milliseconds
(хотя в этом случае вместо этого следует использовать {1,3}
и {1,5}
). Конечный термин .[^\n]
выглядит так, как будто он пытается исключить метки времени, которые находятся в конце строки или рядом с ним. Журналы с временными метками часто имеют временную метку, за которой следует какой-либо символ-разделитель (:
, >
, пробел и т. д.). Подобное регулярное выражение можно использовать для извлечения временных меток из журнала, игнорируя «пустые» строки, которые имеют временную метку, но не содержат сообщения.
Обновление. Вот пример использования TCL 8.4:
% set re ".* (\[\\d]\{3\}:\[\\d]\{3\}:\[\\d]\{3\}.\[\\d]\{5\}).\[^\\n]"
% regexp $re "TEST: 123:456:789:12345> sample log line"
1
% regexp $re " 111:222:333.44444 foo"
1
% regexp $re "111:222:333.44444 foo"
0
% regexp $re " 111:222:333.44444 "
0
% regexp $re " 10:44:56.12344: "
0
%
% regexp $re "TEST: 123:456:789:12345> sample log line" match data
1
% puts $match
TEST: 123:456:789:12345>
% puts $data
123:456:789:12345
Первые два примера соответствуют выражению. Третий терпит неудачу, потому что ему не хватает символа пробела перед первой числовой последовательностью. Четвертый терпит неудачу, потому что у него нет символа новой строки в конце после завершающего пробела. Пятый терпит неудачу, потому что числовые последовательности не имеют достаточного количества цифр. Передавая параметры после ввода, вы можете сохранить часть ввода, которая соответствует выражению, а также данные, которые были «захвачены» с помощью круглых скобок. Подробнее о команде regexp
см. вики TCL.
Интересная часть TCL заключается в том, что вам нужно экранировать символ [
, но не ]
, в то время как {
и }
нужно экранировать.
[\d]
и \d
полностью эквивалентны.
- person Donal Fellows; 17.04.2012
\[\\d]
видится как [\d]
, когда механизм регулярных выражений получает ее, поэтому она будет соответствовать цифре, а не букве 'd'. См. мой ответ для примеров (вы можете добавить puts $re
, чтобы увидеть выражение после обработки побегов).
- person bta; 17.04.2012
.(?:$|\[^\\n])
чтобы попасть в конец строки или символ, не являющийся новой строкой. - person glenn jackman   schedule 17.04.2012