Регулярное выражение от подстроки к первому вхождению другой подстроки

690
Robert Koszegi

Мне нужно исключить файлы textClipping из списка. К сожалению, некоторые файлы были ужасно названы и содержат возврат каретки. Мне нужно PERL регулярное выражение для этого будет соответствовать каждый путь от /Volumes/до, .textClippingвключая символ новой строки.

/Volumes/.*\.textClippingзахватывает первые два .textClippingфайла, но не третий, с новой строкой. Кроме того, я смог захватить все от первого /Volumes/до последнего .textClipping, но это тоже не помогает.

Есть идеи? Огромное спасибо.

/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi   le.textClipping /Volumes/folder/folder/file.doc 
0

3 ответа на вопрос

0
FosseWay

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

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

Я сделал этот скрипт:

#!/usr/bin/perl  $filename = "filelist.txt";  open(FILE, $filename) or die "Cant open $filename\n";   # Undefine the record separator, so that the entire file will be read into a single string # instead of an array with records separated by newlines local $/ = undef;  $lines = <FILE>;  close(FILE);  print "Before\n------\n";  print $lines;   # Remove all newlines  $lines =~ s/\n+//g;  # Remove all "textClipping" files $lines =~ s/\/Volumes\/[^ ]*.textClipping//g;  # Turn multiple consecutive spaces into single spaces $lines =~ s/ +/ /g;   print "After\n-----\n";  print "$lines\n";  

и скормил свой пример как filelist.txt:

/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi le.textClipping /Volumes/folder/folder/file.doc 

который дал этот вывод:

Before ------ /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi le.textClipping /Volumes/folder/folder/file.doc After ----- /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc 

Наконец, я думаю, что вы должны быть очень осторожны, используя шаблон, который вы предлагаете в своем вопросе:

/Volumes/.*.textClipping 

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

/Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi le.textClipping /Volumes/folder/folder/file.doc 

и получил этот вывод, который я не думаю, что вы хотите:

/Volumes/folder/folder/fi le.textClipping /Volumes/folder/folder/file.doc 

Изменить : вы недавно опубликовали ответ на свой вопрос, где вы снова попали в эту ловушку, но у меня недостаточно репутации, чтобы оставить комментарий к ней. Вместо /Volumes/.*\n*.textClipping/g(который будет совпадать с пробелами и, следовательно, потенциально избавляться от более чем одного имени файла за раз), я настоятельно рекомендую вам рассмотреть /Volumes/[^ ]*\n*.textClipping/g; [^ ]*будет соответствовать все, кроме пробелов.

0
Toto

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

perl -0777 -ae '@files = m~(/Volumes/(?:[^/\r\n]+/)+?[^/]+?\.textClipping\R)~g;print scalar(@files)," files found:\n",@files' file.txt 

Куда:

  • -0777 прочитать файл в режиме "slurp"
  • -a режим автоматического разделения

Regex:

 ~ : regex delimiter ( : start group 1 /Volumes/ : literally  (?: : start non capture group [^/\r\n]+ : 1 or more any character that is not a slash or line break / : slash )+? : group repeated 1 or more times, not greedy (ie. the path) [^/]+? : not a slash, 1 or more times, not greedy (ie. the filename) \.textClipping : a dot with the extension \R : any kind of linebreak ) : end group 1 ~g : regex delimiter, global flag 

Выход:

3 files found: /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/file.textClipping /Volumes/folder/folder/fi  le.textClipping 

Если вы хотите сохранить все файлы, которые не заканчиваются .textClipping

perl -0777 -i.orig -ape 's~(/Volumes/(?:[^/\r\n]+/)+?[^/]+?\.textClipping\R)~~g' file.txt 

Входной файл изменяется на месте (опция -i), исходный файл резервируется с расширением.orig

cat file.txt /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc /Volumes/folder/folder/file.doc 
0
Robert Koszegi

Я действительно ценю ответы. Спасибо за ваше время. Я извиняюсь, если что-то не было ясно в моем вопросе. Ответ оказался проще, чем я думал вначале.

Следует отметить, что возврат каретки или новая строка в имени файла выглядит следующим образом: «file (CR) name.textClipping». Текстовые файлы просто дают текст, содержащийся внутри, в качестве имени самого файла, что в моем случае - несколько возвратов каретки. Боль в заднице!

Тем не менее, это работает: /Volumes/.*\n*.textClipping/g

Это совпадает со строками вхождений, начинающимися с "/ Volumes /" и заканчивающимися на ".textClipping" со всем, что между ними.

Еще раз спасибо за ваши предложения.

Вы уверены, что это работает, как вы хотите? Применить к данному файлу примера, он дает для второго совпадения 2 файла (строка 3 соединяется со строкой 4) Toto 6 лет назад 0

Похожие вопросы