#regex #bash #perl #sh #regex-lookarounds
#регулярное выражение #bash #perl #sh #поиск регулярных выражений
Вопрос:
Вот пример моих данных:
SomePascalCase.wav
ThingsThat1.wav
Are.wav
Here.wav
Вот результат, который я ищу:
some-pascal-case.wav
things-that-1.wav
are.wav
here.wav
Вот что я использовал:
for f in *.wav; do
mv "$f" $(
echo "$f" |
perl -pe 's/([A-Z])([a-z] )(?=[0-9A-Z])/L12-/g' |
perl -pe 's/([A-Z])([a-z] )(?=.wav)/L12/g'
)
done
Возможно ли объединить два регулярных выражения, которые я использовал, в одно?
Комментарии:
1. Вы не должны использовать
1
and2
в выражении замены; вы должны использовать$1
and$2
.2. IIRC, perl RES завершены по Тьюрингу, поэтому вы можете делать буквально все, что угодно, одним RE. Если вы, хотя … конечно, это совсем другой вопрос.
3. В вашем шаблоне есть ошибка. Вы хотите
.wav
, а не.wav
Ответ №1:
На самом деле вы бы не использовали здесь подстановку регулярных выражений. Вы бы использовали split
, а затем join
с тире. split
Шаблон представляет собой отрицательный взгляд назад, за которым следует взгляд вперед.
lc join "-", split /(?<=[a-z])(?=[A-Z])/;
Например
pp split /(?<=[a-z])(?=[A-Z])/, "FooBarBaz"
("Foo", "Bar", "Baz")
В зависимости от ваших правил разделения чисел, вы бы просто добавили дополнительные проверки границ с помощью обхода.
pp split /(?<=[a-z])(?=[A-Z])|(?<=[A-Za-z])(?=[d])|(?<=[d])(?=[A-Za-z])/, "Foo1BarBaz1"
("Foo", 1, "Bar", "Baz", 1)
Редактировать
Чтобы включить это в свой один лайнер, вы должны сделать это:
f=FooBarBaz1
echo $( echo "$f" | perl -pe '$_ = lc join "-", split /(?<=[a-z])(?=[A-Z])|(?<=[A-Za-z])(?=[d])|(?<=[d])(?=[A-Za-z])/;' )
foo-bar-baz-1
Выполнение этого с заменами только усложнит задачу.
HTH
Комментарии:
1. ни одна из этих команд не работает в bash или zsh. я также хочу использовать s/pattern/replacement/, так что это не отвечает на мой вопрос.
2. Я обновил ответ, чтобы использовать вашу командную строку.
3. Если вы хотите использовать что-то подобное
pp
, расскажите людям, что это такое. Поскольку вы просто печатаете здесь список, я не вижу преимущества в дополнительных, неосновных материалах Perl.4. Я не согласен с вами в этом, но я просто оставил это, потому что это была просто иллюстрация.
Ответ №2:
Я понимаю ваши требования:
- Он должен работать
bash
как однострочный. - Он преобразует строку имени файла с помощью одного s / pattern / replacement / operator .
Тогда как насчет:
for f in *.wav; do mv "$f" "$(echo "$f" | perl -pe 's/(^|[a-z])([A-Z0-9])/ $1 eq "" ? lc($2) : $1 . "-" . lc($2) /ge')"; done
e
Опция дляs/pattern/replacement/
оператора позволяет замене быть выражениемperl
.
Комментарии:
1. Спасибо! я не знал, что вы можете использовать sprintf в подобном регулярном выражении perl. аккуратно!
2. ДА. Я добавил краткое объяснение этой
e
опции. BR.3.
s/.../.../
в основном это сокращение отs/.../ "..." /e
. Вы можете поместить любой код в выражение замены (не в регулярное выражение).4. Это
sprintf
было совершенно бесполезно, поэтому я удалил его.
Ответ №3:
perl -pe 's/([A-Z])([a-z] )(?=[0-9A-Z])/L12-/g' |
perl -pe 's/([A-Z])([a-z] )(?=.wav)/L12/g'
может быть уменьшен до почти эквивалентного
perl -pe's/[a-z]K[A-Zd]/-$amp;/g; s/[A-Z]/L$amp;/g'
или просто
perl -pe's/[a-z]K[A-Zd]/-$amp;/g; $_=lc'
(Технически, вы даже можете удалить это пространство.)
Например,
$ echo FooBar1.wav | perl -pe's/[a-z]K[A-Zd]/-$amp;/g; $_=lc'
foo-bar-1.wav
Для 100% эквивалентности вам потребуется
perl -pe's/([A-Z][a-z] )(?:(?=[A-Zd])|(?=(.wav)))/ "L$1" . ( $2 ? "" : "-" ) /eg'
(Вы даже можете удалить все эти пробелы.)
Например,
$ echo ABCdef.wav | perl -pe's/([A-Z][a-z] )(?:(?=[A-Zd])|(?=(.wav)))/ "L$1" . ( $2 ? "" : "-" ) /eg'
ABcdef.wav
Ответ №4:
Если нужно получить это внутри одной команды подстановки, это можно сделать следующим образом:
perl -pe 's/. ?(?=[A-Z0-9.])/($i ?"-":"").lc$amp;/ge'
Это соответствует любому набору символов, за которым следует заглавная, цифра или точка. Условие проверяет, является ли это первым совпадением или более поздним. Если более позднее, оно добавляет дефис к версии в нижнем регистре соответствующей подстроки.