Reputation: 133
I want to rename files using Ant maintaining their directory structure.
e.g. Assume following directory structure:
- copy
- new
- testthis.a
Using code below, I could rename files containing "this" word to "that.a" using copy task, but they all are getting pasted into "paste" directory loosing their directory structure.
<copy todir="paste" overwrite="true">
<fileset dir="copy"/>
<regexpmapper from="^(.*)this(.*)\.a$$" to="that.a"/>
</copy>
Output:
- paste
- that.a
If I change regexmapper to (notice \1 before that.a):
<regexpmapper from="^(.*)this(.*)\.a$$" to="\1that.a"/>
It's generating correct directory structure but always prepends word before "this" to "that.a"
Output:
- paste
- new
- testthat.a
Is there any way to rename files maintaining their directory structure without pre-pending or appending any word?
Is there any other mapper which can be used for the same?
Any help would be appreciated.
Upvotes: 3
Views: 658
Reputation: 7041
<copy todir="paste" verbose="true">
<fileset dir="copy" includes="**/*this*.a"/>
<regexpmapper from="((?:[^/]+/)*)[^/]+$$" to="\1that.a" handledirsep="true"/>
</copy>
First, setting handledirsep="true"
allows us use forward slashes to match backslashes. This makes the regular expression a bit cleaner.
Next, I'll explain the gnarly regex by breaking it into parts.
I explode ((?:[^/]+/)*)
into...
(
(?:
[^/]+
/
)
*
)
What the parts mean:
( -- capture group 1 starts
(?: -- non-capturing group starts
[^/]+ -- greedily match as many non-directory separators as possible
/ -- match a single directory-separator character
) -- non-capturing group ends
* -- repeat the non-capturing group zero-or-more times
) -- capture group 1 ends
The above parts repeatedly match as many subdirectories as possible. The (
and )
put all of the matches into capture group 1. Later, capture group 1 can be used in the to
attribute of <regexpmapper>
with a \1
backreference.
If there are no /
directory separators in a path, then the above parts won't match anything and capture group 1 will be an empty string.
Moving to the end of the regex, the $$
anchors the regex to the end of each path selected by the <fileset>
.
In the double dollar-sign expression, $$
, the first $
escapes the second $
. This is necessary because Ant would treat a single $
as the start of a property reference.
The [^/]+
matches just the filename because it matches all characters at the end of the path that aren't directory separators (/
).
Given the following directory structure...
- copy (dir)
- new (dir)
- notthis.b
- testthis.a
- anythis.a
...Ant outputs...
[copy] Copying 2 files to C:\ant\paste
[copy] Copying C:\ant\copy\anythis.a to C:\ant\paste\that.a
[copy] Copying C:\ant\copy\new\testthis.a to C:\ant\paste\new\that.a
Upvotes: 3
Reputation: 15758
Try this regexpmapper
:
<regexpmapper from="^(.*)/([^/]*)this(.*)\.a$$" to="\1/that\3"/>
This cuts the path (\1
) and filename prefix (\2
), so you can preserve the directory structure.
Also, you can preserve the file extension if you use \3
in the replacement string.
Upvotes: 0