Zastępowanie znaków we właściwości Ant

90

Czy istnieje prosty sposób na pobranie wartości właściwości, a następnie skopiowanie jej do innej właściwości z zastąpieniem pewnych znaków?

Powiedz propA=This is a value. Chcę zamienić wszystkie spacje na podkreślenia, w wyniku czego propB=This_is_a_value.

aberrant80
źródło

Odpowiedzi:

89

Użyj zadania propertyregex z Ant Contrib .

Myślę, że chcesz:

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

Niestety podane przykłady nie są zbyt jasne, ale warto spróbować. Sprawdź też, co się stanie, jeśli nie ma żadnych podkreśleń - być może będziesz musiał skorzystać z tej defaultValueopcji.

Jon Skeet
źródło
3
Dodawanie defaultValue="${propA}"jest idealne jako ogólne wyszukiwanie / zamiana jednowierszowa: w przeciwnym razie, jeśli nie ma dopasowania, nic nie jest umieszczane w propB !! Dzięki!
David Robson
107

Oto rozwiązanie bez skryptów i bez zewnętrznych plików jar, takich jak ant-conrib:

Sztuczka polega na wykorzystaniu zasobów ANT:

  • Istnieje jeden typ zasobu o nazwie „propertyresource”, który jest podobny do pliku źródłowego, ale zapewnia strumień z wartości ciągu tego zasobu. Możesz więc go załadować i użyć w dowolnym zadaniu, takim jak „kopiowanie”, które akceptuje pliki
  • Istnieje również zadanie „loadresource”, które może załadować dowolny zasób do właściwości (np. Pliku), ale to może również załadować nasz propertyresource. To zadanie pozwala na filtrowanie danych wejściowych poprzez zastosowanie niektórych przekształceń tokenów. Wreszcie następujące rzeczy zrobią, co chcesz:
<loadresource property="propB">
  <propertyresource name="propA"/>
  <filterchain>
    <tokenfilter>
      <filetokenizer/>
      <replacestring from=" " to="_"/>
    </tokenfilter>
  </filterchain>
</loadresource>

Ten zamieni wszystkie „” w propA na „_” i umieści wynik w propB. „filetokenizer” traktuje cały strumień wejściowy (naszą właściwość) jako jeden token i umieszcza na nim zastąpienie ciągu.

Możesz wykonać inne wymyślne transformacje za pomocą innych filtrów tokenów: http://ant.apache.org/manual/Types/filterchain.html

Uwe Schindler
źródło
7
Dzięki! Okazuje się, że możesz nawet upuścić <filetokenizer/>bit. Twój kod działa bez niego (przynajmniej na Ant v1.8.3).
Matthias
Jeśli próbujesz to zrobić z poziomu Maven, zobacz stackoverflow.com/a/22969187/2163960
user2163960
3
Głosuj za techniką, która działa w wersji waniliowej anti nie wymaga dodatkowych bibliotek.
Christopher Schultz,
57

Jeśli ant-contrib nie jest opcją, oto przenośne rozwiązanie dla Java 1.6 i nowszych:

<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>
dnault
źródło
6
W przypadku użycia tej metody dobrze byłoby dołączyć skrypt do CDATA, aby uniknąć problemów z analizowaniem XML. <script language = "javascript"> <! [CDATA [// kod skryptu java może bezpiecznie używać znaku „<”. ]]> </script>
Jan Arciuchiewicz
3
@dnault Javascript nie ma replaceAllfunkcji dla ciągów. Użyj before.replace( /\s/g, "_" )zamiast tego.
Larry Battle
3
@LarryBattle project.getProperty()zwraca a java.lang.String, więc replaceAll()jest to odpowiednie w tym przypadku. Jeśli chcesz użyć replace(), możesz przekonwertować „przed” na natywny ciąg JavaScript za pomocą:before = new String(before);
dnault
1
project.setNewPropertybyłoby bardziej przenośne, ponieważ setPropertymogłoby nadpisać starą wartość właściwości. Mógłby nawet napisać do beforenieruchomości.
Jarekczek
Wymaga Rhino
vintproykt
26

W przypadku, gdy chcesz rozwiązanie, które używa Ant Zabudowy tylko , rozważ to:

<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>

Wyjście jest ${propB} = "This_is_a_value"

mgaert
źródło
2
Kto czyści some.tmp.file?
ceving
Ponieważ inni mogą chcieć tego użyć; Dodaj <delete file = "some.tmp.file" /> po </loadfile>. Answers @ceving Question :)
terix2k11
8

Użyj zewnętrznej aplikacji, takiej jak sed:

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

Jeśli używasz systemu Windows, zacznij googlować w poszukiwaniu „gnuwin32 sed”.

Komenda s/_/./gzastępuje każdy _z . tego skryptu idzie dobrze pod oknami. Pod linux arg może wymagać cytowania.

Jarekczek
źródło
8

Dwie możliwości:

poprzez zadanie skryptu i wbudowany silnik javascript (jeśli używasz 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>

lub używając dodatku Ant 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>

aby nadpisać istniejącą właściwość propA, po prostu zamień propB na propA

Rebse
źródło
7

Oto bardziej uogólniona wersja odpowiedzi Uwe Schindlera :

Możesz użyć macrodefdo utworzenia zadania niestandardowego.

<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>

możesz tego użyć w następujący sposób:

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

będzie to bardzo przydatne, jeśli robisz to wiele razy

Avinash R.
źródło
3

Dodanie odpowiedzi bardziej kompletnego przykładu w stosunku do poprzedniej odpowiedzi

<property name="propB_" value="${propA}"/>
<loadresource property="propB">
  <propertyresource name="propB_" />
  <filterchain>
    <tokenfilter>
      <replaceregex pattern="\." replace="/" flags="g"/>
    </tokenfilter>
  </filterchain>
</loadresource>
Jin Kwon
źródło
1

Tylko FYI do odpowiedzi. Zastępowanie znaków we właściwości Ant - jeśli próbujesz użyć tego wewnątrz wykonania mavena, nie możesz bezpośrednio odwoływać się do zmiennych maven. Będziesz potrzebował czegoś takiego:

...
<target>
<property name="propATemp" value="${propA}"/>
    <loadresource property="propB">
    <propertyresource name="propATemp" />
...
user2163960
źródło
Jakie części związane z wymianą " "do "_"?
Jin Kwon
Alternatywnie w Maven, można uniknąć konieczności użycia własności propATemp poprzez zastąpienie <propertyresource name="propATemp"/>z<string value="${propA}"/>
Ed Randall
1

Właściwości nie można zmienić, ale zmienne antContrib ( http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html ) mogą.

Oto makro do znalezienia / zamiany na zmiennej:

    <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>

Następnie wywołaj makro na przykład:

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

Powyższy kod używa podziału javascript, a następnie złączenia, co jest szybsze niż regex. Właściwości „lokalne” są przekazywane do JavaScript, więc nie ma wycieku właściwości.

River Rock
źródło
0

Lub ... Możesz także spróbować własnego zadania

KOD JAVA:

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>

KONSOLA:

run:
     [echo] propA=This is a value
     [echo] propB=This_is_a_value
samuelbravolopez
źródło