2014-01-10 3 views
0

Я пытаюсь разобрать текстовый файл, используя регулярные выражения perl. Вот набор примеров данных:Perl regex: соответствие первого экземпляра строки после заданного совпадения

"Field1", "Field2", "Field3", "Field4", "Field5" 
"val1-1", "\\path\to\val1-2.txt", "val1-3", "\\path\to\val1-4.ini", "val1-5.txt" 
"val2-1", "val2-2", "\\path\to\val2-3.txt", "\\path\to\val2-4.ini", "val2-5.txt" 
"\\path\to\val3-1.txt", "val3-2", "val3-3", "\\path\to\val3-4.ini", "val3-5.txt" 

Для каждой строки текста, я пытаюсь соответствовать первому экземпляру .txt имени файла; полужирные подстроки в приведенном выше наборе данных.

Я думал, что это будет работать:

while(<INFILE>) { 
    if(m/\\(.*?\.txt)"/) { 
     print "$1\n"; 
    } 
} 

Выход:

\path\to\val1-2.txt 
\path\to\val2-3.txt 
\path\to\val3-1.txt 

, но это не потому, что он будет соответствовать полному пути, а не только имя файла.

Сейчас это работает:

while(<INFILE>) { 
    if(my @matches = $_ =~ m/(.*?)"/g) { 
     foreach (@matches) { 
      print "$1\n" if(m/.*\\(.*?\.txt)/); 
     } 
    } 
} 

Выход:

val1-2.txt 
val2-3.txt 
val3-1.txt 

Но я предполагаю, что должен быть способ сделать это с выражением одного матча?

ответ

1

Как насчет:

my $re = qr~\\([^\\"]+)"~; 
while(<DATA>) { 
    chomp; 
    if(my @m = /$re/g) { 
     say "@m"; 
    } 
} 

__DATA__ 
"Field1", "Field2", "Field3", "Field4", "Field5" 
"val1-1", "\\path\to\val1-2.txt", "val1-3", "\\path\to\val1-4.ini", "val1-5.txt" 
"val2-1", "val2-2", "\\path\to\val2-3.txt", "\\path\to\val2-4.ini", "val2-5.txt" 
"\\path\to\val3-1.txt", "val3-2", "val3-3", "\\path\to\val3-4.ini", "val3-5.txt" 

выход:

val1-2.txt val1-4.ini 
val2-3.txt val2-4.ini 
val3-1.txt val3-4.ini 

Если вы хотите только первый .txt, сделайте следующее:

my $re = qr~\\([^\\"]+\.txt)~; 
while(<DATA>) { 
    chomp; 
    /$re/ && say $1; 
} 
+0

OP сказал, что хочет первый '.txt', поэтому нет необходимости в' .ini', я думаю. Однако цитируемое регулярное выражение является хорошей идеей. :) – simbabque

+0

@simbabque: Не уверен, но я отредактировал свой ответ. – Toto

+0

@simbabque верен: нет необходимости в .ini. Вот как я перевел ваше регулярное выражение на всякий случай, это также поможет кому-то еще: '[^ \\"] '==> сопоставить все, что НЕ \ или". '+' ==> как минимум один раз. Поэтому '[^ \\"] + \. Txt' становится: соответствует любой строке, разделенной символами \ или "и длина которой составляет как минимум один символ и заканчивается на .txt. – user3180957

1

Попробуйте это:

while (<DATA>) { 
    if(m/([^\\]+\.txt)"/) { 
     print "$1\n"; 
    } 
} 

__END__ 
val1-2.txt 
val2-3.txt 
val3-1.txt 

Вам не нужен \ за пределами вашей группы захвата. Вместо этого, ищите все, что не является обратным слэшем, а не просто всем. Поскольку вы хотите, чтобы файл имел имя перед .txt, вам нужен квантор +, а не *?, который равен , что-то или ничего, но получите как можно меньше.

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