问题
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 thes/pattern/replacement/
operator enables the replacement to be an expression ofperl
.
回答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