2012-06-12 8 views
4

Утилита переименования Perl отлично справляется с повседневной работой с файлами, особенно наедине, когда я периодически проверяю свою коллекцию MP3.Как изменить частичные подстроки на смешанный фрейм в Perl

Некоторые люди имеют страшная привычка всегда прописными буквами имя артиста, как это

03 - ARTIST NAME - Song Title.mp3 

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

03 - Artist Name - Song Title.mp3 

Однако это также должно быть сделано разумным способом.

Там могут быть французские или итальянские названия, как:

05 - JEAN BAGUETTE - Honi soit qui mal y pense.mp3 

или

07 - SIGNORE AL FORNO - Pazzi sono tutti i calciatori.mp3 

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

Один подход, который не работал, был

rename 's/(\d{1,2} -)([A-Z ]+)([\s\S]+)/$1lc($2)$3/' filename 

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

Я также попытался заменить $2 на временную переменную (так как мне не разрешено изменять $ 2, поскольку она доступна только для чтения), и перед печатью результата нужно сделать lc(), но мне это не удалось. Во всяком случае, я совершенно новичок Perl.

+0

Итак, вы хотите изменить все между первой парой дефисов в смешанном случае? – Borodin

ответ

3

Самый ясный способ, которым я знаю, это сделать двухэтапную оценку (с использованием модификатора /e).

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

Внутренний один принимает $1 - имя исполнителя - и заменяет все подпоследовательности символов без пробелов с одной и той же строки, первая в нижнем регистре с lc, а затем капитализируется с ucfirst.

В завершение программа напечатает имена до и после. Удалите # из строки переименования, чтобы выполнить переименование.

use strict; 
use warnings; 

my @data = (
    '05 - JEAN BAGUETTE - Honi soit qui mal y pense.mp3', 
    '07 - SIGNORE AL FORNO - Pazzi sono tutti i calciatori.mp3', 
); 

for my $file (@data) { 

    (my $new = $file) =~ s{(-[^-]+-)}{ 
    (my $artist = $1) =~ s/(\S+)/ucfirst lc $1/eg; 
    $artist; 
    }e; 

    print "$file\n"; 
    print "$new\n"; 
    print "\n"; 
    # rename $file, $new; 
} 

выход

05 - JEAN BAGUETTE - Honi soit qui mal y pense.mp3 
05 - Jean Baguette - Honi soit qui mal y pense.mp3 

07 - SIGNORE AL FORNO - Pazzi sono tutti i calciatori.mp3 
07 - Signore Al Forno - Pazzi sono tutti i calciatori.mp3 

Update

Другим способом вы могли бы, чтобы разделить имя файла на дефис, редактировать вторую часть и присоединиться к ним обратно вместе.

Основной цикл сверху становится

for my $file (@data) { 

    my @file = split /-/, $file; 
    $file[1] =~ s/(\S+)/ucfirst lc $1/eg; 
    my $new = join '-', @file; 

    print "$file\n"; 
    print "$new\n"; 
    print "\n"; 
    # rename $file, $new; 
} 

, а функциональность и выход неизменным.


Update 2

Я просто экспериментировали с использованием /-.*?-/ затем с помощью SUBSTR ($ _ $ - [0], $ + [0]), как lvalue for = ~ s ///, но, к сожалению, это не сработало

Это казалось такой опрятной идеей, с которой мне пришлось поэкспериментировать.

Ваш звонок substr неверен, так как $-[0] и $+[0] являются смещениями в строку. Третий параметр substr должен быть строкой длина поэтому вам нужно написать substr($_, $-[0], $+[0] - $-[0])

Этот код работает отлично, и снова производит те же результаты, как и до

for my $file (@data) { 

    next unless $file =~ /-[^-]+-/; 
    my $new = $file; 
    substr($new, $-[0], $+[0]-$-[0]) =~ s/(\S+)/ucfirst lc $1/eg; 

    print "$file\n"; 
    print "$new\n"; 
    print "\n"; 
    # rename $file, $new; 
} 
+0

Да, это может быть лучший способ. Я просто экспериментировал с использованием '/-.*?-/', а затем использовал' substr ($ _, $ - [0], $ + [0]) 'как lvalue для' = ~ s /// ', но, к сожалению, это не работает. – ephemient

+0

@ephemient: Благодарю вас за отличную идею! Я снова обновил свой ответ, работая правильно. Новая идиома для Perl. – Borodin

+1

Не нужно делать '/ e', когда мы имеем' \ u' и '\ L' в правой части. – tchrist

2

Вы можете использовать управляющие последовательности для ucfirst (\u) и lc (\L) в своем регулярном выражении, в сочетании с упреждением утверждением, что требует дальнейшей черточки впереди:

perl -pe 's/(\w)(\w+)(?=.*-)/\u$1\L$2/g' 

Если вы хотите быть более точными, вы можете использовать \pL (буквы) вместо \w. Я предполагаю, что это будет работать с инструментом rename.

ETA: Обновлено для использования \u вместо \U.

+0

Вы хотите '\ u' для первого, а не' \ U'. – tchrist

+0

@tchrist На самом деле, поскольку '$ 1' - всего одна буква, это не имеет большого значения. Но я полагаю, что это можно было бы упростить до 's/(\ w +) (? =. * -)/\ u \ L $ 1/g'. – TLP

+2

Нет, это неправда. Верхний регистр и заголовок являются * не * одним и тем же карточным кодом для всех возможных кодовых точек. Точно так же на первый взгляд формально некорректно отображать до lc, а затем либо tc, либо uc. Вы должны написать '\ u $ 1 \ L $ 2', а не' \ u \ L $ 2'. Да, есть только шесть кодовых пунктов, где это имеет значение: U + 0130, U + 03F4, U + 1E9E, U + 2126, U + 212A и U + 212B. – tchrist