Регулярное выражение не совпадает с данными и датами - PullRequest
1 голос
/ 07 ноября 2011

У меня есть дамп SQL Select с множеством строк, каждая из которых выглядит следующим образом:

07/11/2011 16:48:08,07/11/2011 16:48:08,'YD','MANUAL',0,1,'text','text','text','text',,,,'text',,,0,0,

Я хочу сделать 2 вещи в каждой строке:

  1. Заменить все даты на Oraclesysdate функция.Даты также могут приходить без часа (например, 07/11/2011).
  2. Заменить все нулевые значения на null string

Вот моя попытка:

$_ =~ s/,(,|\n)/,null$1/g;                  # Replace no data by "null"
$_ =~ s/\d{2}\/\d{2}\/d{4}.*?,/sysdate,/g;  # Replace dates by "sysdate"

Но это преобразовало бы строку в:

07/11/2011 16:48:08,07/11/2011 16:48:08,'YD','MANUAL',0,1,'text','text','text','text',null,,null,'text',null,,0,0,null

, хотя я ожидаю, что она будет

sysdate,sysdate,'YD','MANUAL',0,1,'text','text','text','text',null,null,null,'text',null,null,0,0,null

Я не понимаю, почему даты не совпадают и почему некоторые ,, не совпадаютзаменены на null.

Любые идеи приветствуются, заранее спасибо.

Ответы [ 4 ]

1 голос
/ 08 ноября 2011

Вы хотите что-то заменить.Обычно предпочтение отдается прогнозам:

$subject =~ s/(?<=,)(?=,|$)/null/g;

Объяснение:

"
(?<=       # Assert that the regex below can be matched, with the match ending at this position (positive lookbehind)
   ,          # Match the character “,” literally
)
(?=        # Assert that the regex below can be matched, starting at this position (positive lookahead)
              # Match either the regular expression below (attempting the next alternative only if this one fails)
      ,          # Match the character “,” literally
   |          # Or match regular expression number 2 below (the entire group fails if this one fails to match)
      \$          # Assert position at the end of the string (or before the line break at the end of the string, if any)
)
"

Во-вторых, вы хотите заменить даты:

$subject =~ s!\d{2}/\d{2}/\d{4}.*?(?=,)!sysdate!g;

Это почти то же самое с вашим оригинальным регулярным выражением.Просто замените последний, с нетерпением.(Если вы не хотите его заменять, не сопоставляйте его.)

# \d{2}/\d{2}/\d{4}.*?(?=,)
# 
# Match a single digit 0..9 «\d{2}»
#    Exactly 2 times «{2}»
# Match the character “/” literally «/»
# Match a single digit 0..9 «\d{2}»
#    Exactly 2 times «{2}»
# Match the character “/” literally «/»
# Match a single digit 0..9 «\d{4}»
#    Exactly 4 times «{4}»
# Match any single character that is not a line break character «.*?»
#    Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
# Assert that the regex below can be matched, starting at this position (positive lookahead) «(?=,)»
#    Match the character “,” literally «,»
1 голос
/ 07 ноября 2011

Вы могли бы сделать это:

$ cat perlregex.pl
use warnings;
use strict;

my $row = "07/11/2011 16:48:08,07/11/2011 16:48:08,'YD','MANUAL',0,1,'text','text','text','text',,,,'text',,,0,0,\n";

print( "$row\n" );
while ( $row =~ /,([,\n])/ ) { $row =~ s/,([,\n])/,null$1/; }
print( "$row\n" );
$row =~ s/\d{2}\/\d{2}\/\d{4}.*?,/sysdate,/g;
print( "$row\n" );

Что приводит к этому:

$ ./perlregex.pl
07/11/2011 16:48:08,07/11/2011 16:48:08,'YD','MANUAL',0,1,'text','text','text','text',,,,'text',,,0,0,

07/11/2011 16:48:08,07/11/2011 16:48:08,'YD','MANUAL',0,1,'text','text','text','text',null,null,null,'text',null,null,0,0,null

sysdate,sysdate,'YD','MANUAL',0,1,'text','text','text','text',null,null,null,'text',null,null,0,0,null

Это, безусловно, можно оптимизировать, но это поможет понять смысл.

1 голос
/ 07 ноября 2011

\d{2}\/\d{2}\/d{4}.*?, не сработало, потому что последний d не был экранирован.
Если , может быть с любой стороны или с началом / концом строки, вы можете сделать это в 2 шага:

шаг 1
s/(?:^|(?<=,))(?=,|\n)/null/g
расширен:

/
  (?:  ^           # Begining of line, ie: nothing behind us
     | (?<=,)      # Or, a comma behind us
  )
     # we are HERE!, this is the place between characters
  (?=  ,           # A comma in front of us
     | \n          # Or, a newline in front of us
  )
/null/g
# The above regex does not consume, it just inserts 'null', leaving the
# same search position (after the insertion, but before the comma).

# If you want to consume a comma, it would be done this way:
s/(?:^|(?<=,))(,|\n)/null$1/xg
# Now the search position is after the 'null,'

шаг 2
s/(?:^|(?<=,))\d{2}\/\d{2}\/\d{4}.*?(?=,|\n)/sysdate/g

Или, вы можете объединить их в одно регулярное выражение, используя модификатор eval:
$row =~ s/(?:^|(?<=,))(\d{2}\/\d{2}\/\d{4}.*?|)(?=,|\n)/ length $1 ? 'sysdate' : 'null'/eg;

В разобранном виде это выглядит так

Если есть вероятность заполнения пробелов без перевода строки, его можно записать как:

$row =~ s/(?:^|(?<=,))(?:([^\S\n]*\d{2}\/\d{2}\/\d{4}.*?)|[^\S\n]*)(?=,|\n)/ defined $1 ? 'sysdate' : 'null'/eg;

0 голосов
/ 07 ноября 2011

Может быть. *?слишком жадный, попробуйте:

$_ =~ s/\d{2}\/\d{2}\/d{4}[^,]+,/sysdate,/g;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...