2013-03-05 2 views
-1

Мне нужно получить дату, которая может быть в 3 возможных форматах.Получить дату в другом формате на Perl?

  1. 11/20/2012
  2. 11.20.2012
  3. 11-20-2012

Как я могу добиться этого в Perl. Я пытаюсь RegEx получить то, что я хочу. Вот мой код.

my @dates = ("Mon 11/20/2012","2012.11.20","20-11-2012"); #array values may vary in every run 
foreach my $date (@dates){ 
    $date =~ /[-.\/\d+]/g; 
    print "Date: $date \n"; 
} 

Я хочу, чтобы результат был. (код выше ничего не печатает)

Date: 11/20/2012 
Date: 2012.11.20 
Date: 20-11-2012 

Где я ошибаюсь? Пожалуйста помоги. Спасибо

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

+1

Не существует (допустимой) причины не использовать модули. Существуют также основные модули, которые обрабатывают время. – TLP

+0

@TLP Это ограничение на моей стороне. Я не могу установить модуль на cygwin Perl, так как я не владею разрешением. Для переупаковки cygwin Perl потребуется несколько месяцев/лет. Я просто хочу, чтобы сценарий был доступен как можно скорее. На самом деле это просто осложнение на моей стороне. – quinekxi

+0

Ваш код работает так, как ожидалось! С чем вы столкнулись? –

ответ

3

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

В любом случае, проблема заключается в

$date =~ /[-.\/\d+]/g; 

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

my ($match) = $date =~ /[-.\/\d]+/g; 
print "Date: $match\n"; 

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

Почему это работает? Поскольку соответствие шаблону в контексте списка возвращает список совпадений, когда используется глобальный модификатор /g.

+0

Почему при поставке() в $ match не печатается дата, она печатает только 1? В противном случае он работает. : D – quinekxi

+1

Применение регулярного выражения 'm //' для строки возвращает разные вещи в зависимости от контекста. В скалярном контексте он возвращает 1 или пустую строку. В контексте списка - если используется модификатор '/ g' - он возвращает список совпадений. Контекст определяется аргументами левой стороны. '$ match' - это скаляр,' ($ match) '- это список из 1 скаляра. Вы также можете использовать круглые скобки '()' для захвата строк, которые затем будут возвращены. – TLP

2

Я настоятельно рекомендую использовать модуль DateTime::Format::Strptime, который имеет богатый набор функциональности. Подумайте не только о синтаксических строках, но и о проверке даты.

2

Почему бы не искать форматы по одному за раз?

=~ m!(\d{2}/\d{2}/\d{2}|\d{4}\.\d{2}\.\d{2}|\d{2}-\d{2}-\d{4})! 

должен сделать трюк. Кроме этого, существует модуль, посвященный датам, которые называются DateTime.

1

Попробуйте сопоставить форматы по очереди. Регулярное выражение ниже соответствует любому из ваших разрешенных разделителей (/, . или -), а затем требуется тот же разделитель через обратную ссылку (10 или \3). В противном случае у вас есть три возможных разделителя раз в два возможных положения за год, чтобы сделать шесть альтернатив в вашем шаблоне.

#! /usr/bin/env perl 

use strict; 
use warnings; 

#array values may vary in every run 
my @dates = ("Mon 11/20/2012","2012.11.20","20-11-2012"); 

my $date_pattern = qr< 
    \b # begin on word boundary 
    (
    (?:   [0-9][0-9] ([-/.]) [0-9][0-9] \2 [0-9][0-9][0-9][0-9]) 
    | (?: [0-9][0-9][0-9][0-9] ([-/.]) [0-9][0-9] \3 [0-9][0-9]) 
) 
    \b # end on word boundary 
>x; 

foreach my $date (@dates) { 
    if (my($match) = $date =~ /$date_pattern/) { 
    print "Date: $match\n"; 
    } 
} 

Выход:

Date: 11/20/2012 
Date: 2012.11.20 
Date: 20-11-2012

На моей первой попытки в коде выше, я имел \2 в альтернативе YYYY-MM-DD, где я должен был \3, которые не смогли соответствовать. Чтобы избавить нас от круглых скобок, version 5.10.0 added named capture buffers.

  • Названы Захват Буферы

Это теперь можно назвать захват скобка в шаблоне и относятся к содержимому перехваченных по имени. Синтаксис именования: (?<NAME>....). Возможно обращение к именованному буфере с синтаксисом \k<NAME>. В коде новые магические хэши %+ и %- могут использоваться для доступа к содержимому буферов захвата.

Используя эту удобную функцию, код выше становится

#! /usr/bin/env perl 

use 5.10.0; # named capture buffers 

use strict; 
use warnings; 

#array values may vary in every run 
my @dates = ("Mon 11/20/2012","2012.11.20","20-11-2012"); 

my $date_pattern = qr! 
    \b # begin on word boundary 
    (?<date> 
    (?:   [0-9][0-9] (?<sep>[-/.]) [0-9][0-9] \k{sep} [0-9][0-9][0-9][0-9]) 
    | (?: [0-9][0-9][0-9][0-9] (?<sep>[-/.]) [0-9][0-9] \k{sep} [0-9][0-9]) 
) 
    \b # end on word boundary 
!x; 

foreach my $date (@dates) { 
    if ($date =~ /$date_pattern/) { 
    print "Date: $+{date}\n"; 
    } 
} 

и производит тот же результат.

В приведенном выше коде еще много повторений. Используя специальный корпус (DEFINE) в сочетании с именованными захватами, мы можем сделать рисунок намного приятнее.

#! /usr/bin/env perl 

use 5.10.0; 

use strict; 
use warnings; 

#array values may vary in every run 
my @dates = ("Mon 11/20/2012","2012.11.20","20-11-2012"); 

my $date_pattern = qr! 
    \b (?<date> (?&YMD) | (?&DMY)) \b 

    (?(DEFINE) 
    (?<SEP> [-/.]) 
    (?<YYYY> [0-9][0-9][0-9][0-9]) 
    (?<MM> [0-9][0-9]) 
    (?<DD> [0-9][0-9]) 
    (?<YMD> (?&YYYY) (?<sep>(?&SEP)) (?&MM) \k<sep> (?&DD)) 
    (?<DMY> (?&DD) (?<sep>(?&SEP)) (?&MM) \k<sep> (?&YYYY)) 
) 
!x; 

foreach my $date (@dates) { 
    if ($date =~ /$date_pattern/) { 
    print "Date: $+{date}\n"; 
    } 
} 

Да, подшаблон имени DMY также соответствует дате в формате MDY. На данный момент этого достаточно, и you ain’t gonna need it.

Смежные вопросы