Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Регулярные выражения > Помогите с простейшим приведением формата времени :)


Автор: Ptr73 5.2.2010, 10:38
Приветствую!
В регулярных выражениях я полный нуб, так что прошу элементарной помощи.
Нужно распарсить строку с временами и привести ее к формату "чч:мм:сс"
Строка наподобие такой:
timestr="1:10:50 1:28 13:41 14:23:10 2:12 1:44"
нужно получить список значений
01:10:50; 00:01:28; 00:13:41; 14:23:10;
любыми методами, но предпочтительно если стандартными методами регулярных выражений и замены по шаблону,
т.к. делаю я это на VBA через regexp и regexp.replace :)

Примерно так:
паттерн для поиска времён
regex.Pattern = "([0-2]?[0-9])?:?([0-5]?[0-9]):([0-5][0-9])?"

a какой паттерн использовать для replace - ума не приложу
endstr = regEx.Replace(timestr, patrnreplace)

Заранее благодарен!

Автор: sir_nuf_nuf 5.2.2010, 10:51
у вас вроде и так в виде чч:мм:сс

на perl - это можно сделать в одну регулярку.

на VB - скорее всего нет. Обратитесь лучше на форум по VB.

Автор: Ptr73 5.2.2010, 11:07
ну так я эту перловую регулярку и прошу smile

прикрутить ее в VB - это уже моя задача

хотя бы просто преобразовать строку 
"1:10:50 1:28 13:41 14:23:10 2:12 1:44"
в 
"01:10:50 00:01:28 00:13:41 14:23:10 ..."

потому как VB выражения вида мм:сс понимает как чч:мм, от чего мне нужно уйти, явно преобразовав все времена к одному формату

а на форумах VB гораздо меньше специалистов по регуляркам, чем на форумах perl и php

Автор: sir_nuf_nuf 5.2.2010, 11:25
Я вас предупреждал  =)
Код

s/([0-2]?[0-9]|):?([0-5]?[0-9]):([0-5][0-9]|)?/ ($1 || '00') . ':' . $2 . ':' . ($3 || '00')/eg;

Дерзайте.


А лучше не мучайтесь - напишите цикл.
На VB - это лучший способ решить эту проблему

Автор: Ptr73 5.2.2010, 11:30
sir_nuf_nuf, во, спасибо! Это примерно то, что мне нужно!
Пошел прикручивать...

а циклом - не интересно, давно хотел себя заставить начать регулярки осваивать smile

Автор: sir_nuf_nuf 5.2.2010, 11:36
Если все таки прикрутите - пришлите код на VB.

Хочу заметить , что в этой регулярке используется модификатор e который по-моему есть только в perl

Автор: Ptr73 5.2.2010, 11:43
Я не знаю, что за модификатор e.
Вот у меня вопрос по приведению к форматам.
Если $2 отсутствует, то он заменяется на 00, а если он скажем ='2', нужно, чтобы он заменился на '02'
как это сделать в шаблоне замены?

может через какой 0+ или 0?

Автор: sir_nuf_nuf 5.2.2010, 11:54
Код

s/([0-2]?[0-9]|):?([0-5]?[0-9]):([0-5][0-9]|)?/ sprintf("%02d:%02d:%02d", ($1 || 0), $2, ($3 || 0))/eg;


Модификатор e - это исполнение PERL кода

Автор: Ptr73 5.2.2010, 13:48
Сделал, хотя и не настолько красиво, насколько рассчитывал.
К сожалению, без цикла не обошлось.

Это выражение
Код

([0-2]?[0-9]|):?([0-5]?[0-9]):([0-5][0-9]|)

в VB некорректно отрабатывает значения вида 12:34, преобразовывая их в 1:2:34

поэтому сделал примерно так:
Код

timestr = "1:10:50 1:28 13:41 14:23:10 2:12 1:44"
regex.Pattern = "(?:(\d)?(\d):)?(\d)?(\d):(\d+)"

Set matches = regex.Execute(timestr)

For i = 0 To matches.Count - 1

        timeline = timeline + CStr(Int(matches(i).SubMatches(0))) + CStr(Int(matches(i).SubMatches(1))) + ":" + CStr(Int(matches(i).SubMatches(2))) + CStr(Int(matches(i).SubMatches(3))) + ":" + CStr(Int(matches(i).SubMatches(4))) + "; "

Next i 

Автор: sir_nuf_nuf 5.2.2010, 14:11
ну, зато сделали.
проблема даже не в этом.
проблема в том, что вам нужно принимать решение в зависимости от того 
нашлось что - то в первой группе или нет.
в perl - это можно сделать с помощью регулярок.
в VB - нет.
Так что цикл вам в любом случае бы пришлось писать.

Автор: Ptr73 5.2.2010, 14:21
да я до сих пор верю, что и на регулярках VB это можно реализовать

вот если бы от цикла избавиться через Replace типа

timeline = regex.Replace(timestr, "$1$2:$3$4:$5")

Проблема в том, чтобы если $i пустые, то они заменялись бы на "0",
а пока - только пустые строки вставляются
вместо "00:01:28" получается ":1:28"

нужно подобрать конструкцию наподобие
timeline = regex.Replace(timestr, "$1|0$2|0:$3|0$4:$5")
вот только у меня все эти |0, ||0, \|0 альтернативы не сработали
ну да ладно, в будущем может удастся решить этот вопрос :)

Автор: sir_nuf_nuf 7.2.2010, 11:09
Ptr73, я тут подумал - действительно можно =)
нужно просто применить несколько регулярок последовательно
что то вроде этого. Если аккуратно написать - будет понятнее чем с циклом. такие регулярки в VB точно есть
Код

$str =~ s/\b(\d:\d{2}:\d{2})\b/0$1/g;
$str =~ s/\b(\d{2}:\d{2})\b/00:$1/g;
$str =~ s/\b(\d:\d{2})\b/00:0$1/g;

Автор: Logo 7.2.2010, 16:28
Цитата(sir_nuf_nuf @ 5.2.2010,  11:36)
Хочу заметить , что в этой регулярке используется модификатор e который по-моему есть только в perl

Такой модификатор (или вызов callback функции, что суть одно и тоже) вроде есть во всех языках. В PHP PCRE точно есть. В JavaScript тоже.

Автор: Ptr73 7.2.2010, 18:26
sir_nuf_nuf, спасибо, сейчас сделаю по подобию.

Возник такой вопрос - а можно ли сделать паттерн для выборки тех частей строки, которые не подпадают под шаблон?
например, все кроме (\b\d{2}:\d{2}:\d{2}\b)
???
чтобы одним Replace() от мусора избавиться

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


Logo, погуглил, вроде в PHP есть, а в JavaScript - не нашел.
Можете ткнуть носом?
Вот, что нашел по регуляркам 

http://msdn.microsoft.com/ru-ru/library/ae5bf541.aspx

http://msdn.microsoft.com/ru-ru/library/az24scfc.aspx

Автор: Logo 8.2.2010, 00:10
http://wdh.suncloud.ru/js09.htm#mreplace
Цитата

Синтаксис: объект.replace(регвыр,строка)
           объект.replace(регвыр,функция)


По возможностям вызов функции - тоже самое код на месте с модификатором e. Удобство разное - код с модификатором e удобнее, если что-то простенькое обработать, функция - при большом коде.

Добавлено через 2 минуты и 59 секунд
В Perl, кстате, тоже можно вызвать функцию - записав ее в строке замены с  модификатором e. Переменные рег выражений глобальные, в функции будут доступны по умолчанию.

Автор: sir_nuf_nuf 8.2.2010, 01:05
Цитата(Logo @  7.2.2010,  16:28 Найти цитируемый пост)
PCRE
 - Perl Core Reg Expr
Про другие языки... спасибо за инфу. 
Видимо действительно есть у многих, но так что бы это можно было записать как часть regex - кажется только в perl.
или нет ?

Автор: Ptr73 8.2.2010, 11:36
Действительно.
В JavaScript можно писать нечто вроде такого

Код

celsius=farenheit.replace("(\d+(\.\d*)?)F\b", function($0,$1,$2) {return((($1-32) * 5/9) + "C")})


http://msdn.microsoft.com/ru-ru/library/efy6s3e6.aspx

К сожалению в VB и VB.NET String.Replace по-другому реализован и Regex.Replace тоже - они не передают $i в функцию.

Сделал примерно так:
Код

timestr = "2 Иван Иванов 1ю  5 1972 12:47:02  +01:53 2 1:17(  4) 2:25(  8) 1:41(15) 1:02:18"
regex.Pattern = "(?:(\d{1,2}):)?(\d{1,2}):(\d{2})"
timestr = regex.Replace(timestr, "00$1:0$2:$3")
regex.Pattern = ".*?0{0,2}(\d{2}):0{0,1}(\d{2}):(\d{2})"
timeline = regex.Replace(timestr, "$1:$2:$3; ")

'timeline = "12:47:02; 00:01:53; 00:01:17; 00:02:25; 00:01:41; 01:02:18; "


Еще не совершенство, но уже близко к нему smile 
Всем спасибо smile 

Автор: Logo 8.2.2010, 12:27
Не могу точно сказать. В PHP можно писать замену в одну строку.
Код

preg_replace('/[a-c]+/e', 'strtoupper($0)', $string); 

Хотя такой способ использует eval TEXT, и в плане производительности менее предпочтителен, чем с callback функцией.

Цитата

Perl Core Reg Expr

Perl Compatible Regular Expressions. Хотя они, конечно, не совсем Compatible. Вообще в Perl самый мощный механизм регэкспов. Есть много вещей, которые есть только в Perl.

Автор: Logo 9.2.2010, 12:01
Ptr73
У .NET  - Методы Replace с MatchEvaluator.
http://msdn.microsoft.com/ru-ru/library/cft8645c.aspx
http://msdn.microsoft.com/ru-ru/library/system.text.regularexpressions.regex.replace.aspx

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)