Is it possible to rename PascalCase1.wav to kebab-case-1.wav with a single perl regex?

时间秒杀一切 提交于 2021-01-29 00:45:00

问题


Here is a sample of my data:

SomePascalCase.wav
ThingsThat1.wav
Are.wav
Here.wav

Here is the result I'm looking for:

some-pascal-case.wav
things-that-1.wav
are.wav
here.wav

Here is what I used:

for f in *.wav; do
   mv "$f" $(
      echo "$f" |
      perl -pe 's/([A-Z])([a-z]+)(?=[0-9A-Z])/\L\1\2-/g' |
      perl -pe 's/([A-Z])([a-z]+)(?=.wav)/\L\1\2/g'
   )
done

Is it possible to consolidate the two regular expressions I used into a single one?


回答1:


You wouldn't really use a regex substitution here. You would use split and then join with dashes. The split pattern is a negative look behind followed by a look ahead.

lc join "-", split /(?<=[a-z])(?=[A-Z])/;

For example

pp split /(?<=[a-z])(?=[A-Z])/, "FooBarBaz"

("Foo", "Bar", "Baz")

Depending on your rules for seperating out numbers, you would just add more boundary checks with look arounds.

pp split /(?<=[a-z])(?=[A-Z])|(?<=[A-Za-z])(?=[\d])|(?<=[\d])(?=[A-Za-z])/, "Foo1BarBaz1"

("Foo", 1, "Bar", "Baz", 1)

EDIT
To incorporate this into your one liner, you would do this:

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

Doing it with substitutions will just make it more complicated.

HTH




回答2:


My understanding of your requirements:

  • It must work in bash as a one-liner.
  • It converts the string of filename with a single s/pattern/replacement/ operator.

Then how about:

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
  • The e option to the s/pattern/replacement/ operator enables the replacement to be an expression of perl.



回答3:


perl -pe 's/([A-Z])([a-z]+)(?=[0-9A-Z])/\L\1\2-/g' |
perl -pe 's/([A-Z])([a-z]+)(?=.wav)/\L\1\2/g'

can be reduced to the nearly equivalent

perl -pe's/[a-z]\K[A-Z\d]/-$&/g; s/[A-Z]/\L$&/g'

or just

perl -pe's/[a-z]\K[A-Z\d]/-$&/g; $_=lc'

(Technically, you can even remove that space.)

For example,

$ echo FooBar1.wav | perl -pe's/[a-z]\K[A-Z\d]/-$&/g; $_=lc'
foo-bar-1.wav

For 100% equivalence, you would need

perl -pe's/([A-Z][a-z]+)(?:(?=[A-Z\d])|(?=(\.wav)))/ "\L$1" . ( $2 ? "" : "-" ) /eg'

(You can even remove all these spaces too.)

For example,

$ echo ABCdef.wav | perl -pe's/([A-Z][a-z]+)(?:(?=[A-Z\d])|(?=(\.wav)))/ "\L$1" . ( $2 ? "" : "-" ) /eg'
ABcdef.wav



回答4:


If need to get this inside one substitution command, it could be done like this:

perl -pe 's/.+?(?=[A-Z0-9.])/($i++?"-":"").lc$&/ge'

This matches any set of characters which is followed by a capital, digit, or dot. The conditional checks if this is the first match or a later one. If a later one, it prepends a hyphen to the lowercased version of the matched substring.



来源:https://stackoverflow.com/questions/65298102/is-it-possible-to-rename-pascalcase1-wav-to-kebab-case-1-wav-with-a-single-perl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!