2014-10-28 2 views
2

Мне нужно поместить файлы в отдельные группы в соответствии с шаблоном в имени файла. Мне нужен идентификатор, который идентифицирует группу, к которой принадлежит файл. Неважно, как формируется этот идентификатор (за исключением того, что он не должен быть пустым), он должен быть одинаковым для всех файлов в группе. Я пытаюсь построить идентификатор непосредственно из файла в соответствии с этим правилом:Как сопоставить эти шаблоны с помощью регулярных выражений?

  • удалить подстроку «Dokument» или «Signatur» с конца базового имени файла и предшествующий «_», если либо строка найдена
  • удалить расширение
  • предшествует результат с фиктивной строкой (например, «ID»), чтобы избежать пустой ID
  • сделано.

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

Вот моя попытка до сих пор:

for (<DATA>) { 
my ($match) = ($_ =~ /(.*?)(?:dokument|signatur)?(?:\..*)/); 
    print $_ . " => id" . $match . "\n"; 
}; 

__DATA__ 
dokument.pdf 
dokument.rtf 
dokument.html 
COO_2026_100_2_dokument.pdf 
COO_2026_100_2.zip 
dokument.xml 
signatur.xml 
COO_2026_100_2_dokument.xml 
COO_2026_100_2_dokument.rtf 
COO_2026_100_2_signatur.xml 
COO_2026_100_3_dokument.xml 

Что должно произойти: - dokument.* и signatur.* идут в одну группу - *_2* перейти в другую группу - *_3* переходит в третью группу

Что Случается, что все в порядке, за исключением zip-File, потому что у него нет «_» в его id. Я подозреваю, что это можно решить, посмотрев вперед, но я понятия не имею. И, может быть, я ошибаюсь.

Любые идеи?

ответ

2

Идея lookahead состоит в том, чтобы соответствовать заданному шаблону, только если за ним следует другой шаблон (который не входит в совпадение). Это трудно следовать именно то, что вы ищете, но если я понимаю, что вы имеете в виду, что это будет работать:

.*?(?=_?(dokument|signatur|\.[^.]+$)) 

Это соответствует всему до любого dokument или signatur и предыдущего _, если есть один или до расширения ни одного из них не присутствует.

Несколько примечаний:

  • Вы не должны соответствовать добавочному послеdokument или signatur, вам нужно только, чтобы соответствовать его, если ни один из тех, кто находится, так как если один из них вы только включаете все, что приходит перед ними (кроме предыдущего _, если есть) в результатах.
  • Соответствие расширению с помощью \..* может работать с этими именами файлов, но это не надежный способ сделать это в целом, потому что, если в имени файла имеется более одной точки, это будет соответствовать всем, начиная с первой точки. \.[^.]+$ гарантирует, что вы начинаете с последней точки.

Кроме того, нет необходимости использовать группу соответствия или присваивать результаты переменной. Просто матч часть имени файла, который вы хотите использовать, и получить его с $ &:..

for (<DATA>) { 
    $_ =~ /.*?(?=_?(dokument|signatur|\.[^.]+$))/; 
    print $_ . " => id" . $& . "\n"; 
} 
+0

Нет, как показывают данные примера, есть файлы, которые просто называются «dokument.xml» или «signatur.xml», поэтому нет «_». Я попробую ваше решение. – jackthehipster

+0

ваше регулярное выражение производит различные идентификаторы, чем мне нужно. Правило в основном заключается в следующем: удалите «имя документа» или «signatur» из имени файла, а остальное - id. За исключением того, что нужно подписаться, это должно пойти так же хорошо. – jackthehipster

+0

Я в замешательстве, вы говорите, что хотите * сохранить * расширение? Регулярное выражение в вашем вопросе подразумевает, что вы хотите его исключить, потому что оно заканчивается символом '(?: \ .. *)'. В противном случае я не понимаю, каким образом он не производит матчи, которые вы ищете. Можете ли вы включить в вопрос, какой именно результат вы хотите для каждого из этих имен файлов? –

0

Конечно, вы можете сделать то, что хотите за один шаг.

my ($id) = /(.*?)(?:_(?:dokument|signatur))?(?:\.[^.]*)?$/; 

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

use strict; 
use warnings; 

for (<DATA>) { 
    chomp; 

    my $id = $_; 
    $id =~ s/\.[^.]*$//;     # Remove Extension 
    $id =~ s/_(?:dokument|signatur)$//; # Remove Suffix 

    print "$_ => id$id\n"; 
} 

__DATA__ 
dokument.pdf 
dokument.rtf 
dokument.html 
COO_2026_100_2_dokument.pdf 
COO_2026_100_2.zip 
dokument.xml 
signatur.xml 
COO_2026_100_2_dokument.xml 
COO_2026_100_2_dokument.rtf 
COO_2026_100_2_signatur.xml 
COO_2026_100_3_dokument.xml 

Выходы:

dokument.pdf => iddokument 
dokument.rtf => iddokument 
dokument.html => iddokument 
COO_2026_100_2_dokument.pdf => idCOO_2026_100_2 
COO_2026_100_2.zip => idCOO_2026_100_2 
dokument.xml => iddokument 
signatur.xml => idsignatur 
COO_2026_100_2_dokument.xml => idCOO_2026_100_2 
COO_2026_100_2_dokument.rtf => idCOO_2026_100_2 
COO_2026_100_2_signatur.xml => idCOO_2026_100_2 
COO_2026_100_3_dokument.xml => idCOO_2026_100_3 
+0

'* Signatur *' и '* Dokument *' принадлежат вместе в той же самой группе, так что они должны получить тот же идентификатор. В противном случае штраф. – jackthehipster

0

Ok Я нашел одно решение , Изменяя рисунок на

my ($match) = ($_ =~ /(.*?)(?:_?(?:dokument|signatur))?(?:\..*)/); 

ведущий _ будет игнорироваться в id, и все в порядке.

Меня все еще интересует решение с использованием lookahead, если это возможно. Я никогда не понимал эту идею.

+0

Здесь нет причин для поиска. Это инструмент, как любой другой, и хорошо, что вы хотите его изучить. Тем не менее, вы не используете отвертку, чтобы вставить гвоздь. – Miller

+0

Я знаю, но здесь я точно понимаю, в чем проблема, и, видя решение, я, вероятно, лучше пойму. Я думал, «если этому документовому знаку предшествует _, удалите это также» ... так что на самом деле это скорее взгляд?!. – jackthehipster

+0

Но вы правы, конечно. Решение - это решение. Зачем беспокоиться. – jackthehipster

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