94

Is there a simple way of taking the value of a property and then copy it to another property with certain characters replaced?

Say propA=This is a value. I want to replace all the spaces in it into underscores, resulting in propB=This_is_a_value.

aberrant80
  • 12,815
  • 8
  • 45
  • 68

11 Answers11

113

Here is the solution without scripting and no external jars like ant-conrib:

The trick is to use ANT's resources:

  • There is one resource type called "propertyresource" which is like a source file, but provides an stream from the string value of this resource. So you can load it and use it in any task like "copy" that accepts files
  • There is also the task "loadresource" that can load any resource to a property (e.g., a file), but this one could also load our propertyresource. This task allows for filtering the input by applying some token transformations. Finally the following will do what you want:
<loadresource property="propB">
  <propertyresource name="propA"/>
  <filterchain>
    <tokenfilter>
      <filetokenizer/>
      <replacestring from=" " to="_"/>
    </tokenfilter>
  </filterchain>
</loadresource>

This one will replace all " " in propA by "_" and place the result in propB. "filetokenizer" treats the whole input stream (our property) as one token and appies the string replacement on it.

You can do other fancy transformations using other tokenfilters: http://ant.apache.org/manual/Types/filterchain.html

Uwe Schindler
  • 1,241
  • 1
  • 8
  • 4
93

Use the propertyregex task from Ant Contrib.

I think you want:

<propertyregex property="propB"
               input="${propA}"
               regexp=" "
               replace="_"
               global="true" />

Unfortunately the examples given aren't terribly clear, but it's worth trying that. You should also check what happens if there aren't any underscores - you may need to use the defaultValue option as well.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 3
    Adding `defaultValue="${propA}"` is perfect as a general search/replace one-liner: otherwise, if there's no match, nothing is put into propB!! Thanks! – David Robson Sep 01 '16 at 13:08
59

If ant-contrib isn't an option, here's a portable solution for Java 1.6 and later:

<property name="before" value="This is a value"/>
<script language="javascript">
    var before = project.getProperty("before");
    project.setProperty("after", before.replaceAll(" ", "_"));
</script>
<echo>after=${after}</echo>
reallynice
  • 1,289
  • 2
  • 21
  • 41
dnault
  • 8,340
  • 1
  • 34
  • 53
  • 6
    If this metod is used it would be good to enclose script in CDATA to avoid problems with xml parsing. – Jan Arciuchiewicz Jul 25 '12 at 14:54
  • 3
    @dnault Javascript doesn't have a `replaceAll` function for strings. Use `before.replace( /\s/g, "_" )` instead. – Larry Battle Aug 04 '12 at 19:04
  • 3
    @LarryBattle `project.getProperty()` returns a `java.lang.String`, so `replaceAll()` is appropriate in this case. If you wanted to use `replace()`, you could convert 'before' to a native JavaScript string with: `before = new String(before);` – dnault Aug 13 '12 at 17:33
  • 1
    `project.setNewProperty` would be more portable, as `setProperty` could overwrite old property value. It could even write to the `before` property. – Jarekczek Oct 11 '12 at 07:38
  • It requires Rhino – vintprox Apr 17 '20 at 09:25
28

In case you want a solution that does use Ant built-ins only, consider this:

<target name="replace-spaces">
    <property name="propA" value="This is a value" />
    <echo message="${propA}" file="some.tmp.file" />
    <loadfile property="propB" srcFile="some.tmp.file">
        <filterchain>
            <tokenfilter>
                <replaceregex pattern=" " replace="_" flags="g"/>
            </tokenfilter>
        </filterchain>
    </loadfile>
    <echo message="$${propB} = &quot;${propB}&quot;" />
</target>

Output is ${propB} = "This_is_a_value"

mgaert
  • 2,338
  • 21
  • 27
8

Two possibilities :

via script task and builtin javascript engine (if using jdk >= 1.6)

<project>

 <property name="propA" value="This is a value"/>

 <script language="javascript">
  project.setProperty('propB', project.getProperty('propA').
   replace(" ", "_"));
 </script>
 <echo>$${propB} => ${propB}</echo>

</project>

or using Ant addon Flaka

<project xmlns:fl="antlib:it.haefelinger.flaka">

 <property name="propA" value="This is a value"/>

 <fl:let> propB := replace('${propA}', '_', ' ')</fl:let>

 <echo>$${propB} => ${propB}</echo>

</project>

to overwrite exisiting property propA simply replace propB with propA

Rebse
  • 10,307
  • 2
  • 38
  • 66
8

Here's a more generalized version of Uwe Schindler's answer:

You can use a macrodef to create a custom task.

<macrodef name="replaceproperty" taskname="@{taskname}">
    <attribute name="src" />
    <attribute name="dest" default="" />
    <attribute name="replace" default="" />
    <attribute name="with" default="" />
    <sequential>
        <loadresource property="@{dest}">
            <propertyresource name="@{src}" />
            <filterchain>
                <tokenfilter>
                    <filetokenizer/>
                    <replacestring from="@{replace}" to="@{with}"/>
                </tokenfilter>
            </filterchain>
        </loadresource>
    </sequential>
</macrodef>

you can use this as follows:

<replaceproperty src="property1" dest="property2" replace=" " with="_"/>

this will be pretty useful if you are doing this multiple times

Community
  • 1
  • 1
Avinash R
  • 3,101
  • 1
  • 27
  • 47
8

Use some external app like sed:

<exec executable="sed" inputstring="${wersja}" outputproperty="wersjaDot">
  <arg value="s/_/./g"/>
</exec>
<echo>${wersjaDot}</echo>

If you run Windows get it googling for "gnuwin32 sed".

The command s/_/./g replaces every _ with . This script goes well under windows. Under linux arg may need quoting.

Jarekczek
  • 7,456
  • 3
  • 46
  • 66
4

Adding an answer more complete example over a previous answer

<property name="propB_" value="${propA}"/>
<loadresource property="propB">
  <propertyresource name="propB_" />
  <filterchain>
    <tokenfilter>
      <replaceregex pattern="\." replace="/" flags="g"/>
    </tokenfilter>
  </filterchain>
</loadresource>
Community
  • 1
  • 1
Jin Kwon
  • 20,295
  • 14
  • 115
  • 184
1

Just an FYI for answer Replacing characters in Ant property - if you are trying to use this inside of a maven execution, you can't reference maven variables directly. You will need something like this:

...
<target>
<property name="propATemp" value="${propA}"/>
    <loadresource property="propB">
    <propertyresource name="propATemp" />
...
Community
  • 1
  • 1
user2163960
  • 1,871
  • 19
  • 22
1

Properties can't be changed but antContrib vars (http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html ) can.

Here is a macro to do a find/replace on a var:

    <macrodef name="replaceVarText">
        <attribute name="varName" />
        <attribute name="from" />
        <attribute name="to" />
        <sequential>
            <local name="replacedText"/>
            <local name="textToReplace"/>
            <local name="fromProp"/>
            <local name="toProp"/>
            <property name="textToReplace" value = "${@{varName}}"/>
            <property name="fromProp" value = "@{from}"/>
            <property name="toProp" value = "@{to}"/>

            <script language="javascript">
                project.setProperty("replacedText",project.getProperty("textToReplace").split(project.getProperty("fromProp")).join(project.getProperty("toProp")));
            </script>
            <ac:var name="@{varName}" value = "${replacedText}"/>
        </sequential>
    </macrodef>

Then call the macro like:

<ac:var name="updatedText" value="${oldText}"/>
<current:replaceVarText varName="updatedText" from="." to="_" />
<echo message="Updated Text will be ${updatedText}"/>

Code above uses javascript split then join, which is faster than regex. "local" properties are passed to JavaScript so no property leakage.

River Rock
  • 79
  • 1
  • 1
0

Or... You can also to try Your Own Task

JAVA CODE:

class CustomString extends Task{

private String type, string, before, after, returnValue;

public void execute() {
    if (getType().equals("replace")) {
        replace(getString(), getBefore(), getAfter());
    }
}

private void replace(String str, String a, String b){
    String results = str.replace(a, b);
    Project project = getProject();
    project.setProperty(getReturnValue(), results);
}

..all getter and setter..

ANT SCRIPT

...
<project name="ant-test" default="build">

<target name="build" depends="compile, run"/>

<target name="clean">
    <delete dir="build" />
</target>

<target name="compile" depends="clean">
    <mkdir dir="build/classes"/>
    <javac srcdir="src" destdir="build/classes" includeantruntime="true"/>
</target>

<target name="declare" depends="compile">
    <taskdef name="string" classname="CustomString" classpath="build/classes" />
</target>

<!-- Replacing characters in Ant property -->
<target name="run" depends="declare">
    <property name="propA" value="This is a value"/>
    <echo message="propA=${propA}" />
    <string type="replace" string="${propA}" before=" " after="_" returnvalue="propB"/>
    <echo message="propB=${propB}" />
</target>

CONSOLE:

run:
     [echo] propA=This is a value
     [echo] propB=This_is_a_value