【问题标题】:Iterate over for loop with fixed amount of iterations以固定的迭代次数迭代 for 循环
【发布时间】:2013-12-14 10:13:09
【问题描述】:

我在我的 ant 脚本中使用 ant-contrib 库,但我不知道如何才能获得固定数量 使用 foreach 标记的循环? 我所说的固定迭代次数并不是指一些硬编码的值,而是从命令行提供的 ant 属性。

【问题讨论】:

    标签: ant ant-contrib


    【解决方案1】:

    以下代码创建了一个固定次数为 5 次迭代的循环:

    <target name="example">
        <foreach param="calleeparam" list="0,1,2,3,4" target="callee"/>
    </target>
    <target name="callee">
        <echo message="${calleeparam}"/>
    </target>
    

    打印出来

    example:
    callee:
         [echo] 0
    callee:
         [echo] 1
    callee:
         [echo] 2
    callee:
         [echo] 3
    callee:
         [echo] 4
    

    编辑

    如果您想要可变数量的迭代,那么您可能想尝试以下方法之一(它们支持的迭代数量和可读性不同)。第一种方法可以处理几次迭代。它使用一个固定列表,该列表使用正则表达式截断以获得固定数量的字符。

    <target name="example1">
        <property name="n" value="17"/>
        <property name="maxlist" value="00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19"/>
        <propertyregex property="list" input="${maxlist}" regexp="(^.{${n}}.{${n}}.{${n}})" select="\1"/>
        <foreach param="calleeparam" list="${list}" target="callee"/>
    </target>
    

    第二种方法可以处理相当多的迭代:它读取一个文本文件并将每个字符替换为X, 以形成一个列表,该列表会像前一种方法一样被截断:

    <target name="example2">
        <property name="n" value="170"/>
        <loadfile property="chars" srcfile="${ant.file}"/><!-- some large text file -->
        <propertyregex property="maxlist" input="${chars}" regexp="((?:.|[\r\n\t]))" replace="X," global="true"/>
        <propertyregex property="list" input="${maxlist}" regexp="(^.{${n}}.{${n}})" select="\1"/>
        <foreach param="calleeparam" list="${list}" target="callee"/>
    </target>
    

    第三种方法使用 JavaScript 为 foreach 准备列表:

    <target name="example3">
        <property name="n" value="330"/>
        <property name="target" value="callee"/>
        <property name="param" value="calleeparam"/>
        <script language="javascript">
        var list="", n=parseInt(project.getProperty("n"),10);
        for (var i = 0; i &lt; n; i++) list += i + ",";  
        project.setProperty("list", list);
        </script>
        <foreach param="calleeparam" list="${list}" target="callee"/>
    </target>
    

    第四种方法不使用foreach,而是使用JavaScript 使用动态创建的antcalls 对目标进行所需数量的调用:

    <target name="example4">
        <property name="n" value="3300"/>
        <property name="target" value="callee"/>
        <property name="param" value="calleeparam"/>
        <script language="javascript">
        // does n antcall's with iteration number param
        var n = parseInt(project.getProperty("n"),10);
        for (var i = 0; i &lt; n; i++) {
            var t = project.createTask("antcall");
            t.setTarget(project.getProperty("target"));
            var p = t.createParam();
            p.setName(project.getProperty("param"));
            p.setValue(""+i);
            t.perform();
        }
        </script>
    </target>
    

    【讨论】:

    • 我编辑了问题:迭代总数未知。
    • 要使上述方法正常工作,您需要像 Brimstedt 指出的那样包含 ant-contrib,您可以通过在项目中添加以下内容来实现:&lt;taskdef resource="net/sf/antcontrib/antcontrib.properties" classpath="/path/to/ant-contrib/ant-contrib-1.0b3.jar"/&gt;
    【解决方案2】:

    ANT 不是编程语言,我也不是 ant-contrib 的粉丝,我认为它试图改进这个功能......

    我的建议是将脚本语言嵌入到您的构建中。 javascript 的优点是它不需要额外的 jar,但我想你会发现 groovy ANT task 非常强大。

    示例

    $ ant -Dtimes=3
    
    loop:
    
    dosomething:
         [echo] hello world
    
    dosomething:
         [echo] hello world
    
    dosomething:
         [echo] hello world
    

    build.xml

    <project name="demo" default="loop">
    
      <property name="times" value="2"/>
    
      <target name="loop">
        <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy"/>
    
        <groovy>
          def count = properties.times.toInteger() 
    
          (1..count).each {
            ant.ant(target: "dosomething")
          }
        </groovy>
      </target>
    
      <target name="dosomething">
        <echo message="hello world"/>
      </target>
    
    </project>
    

    可以添加一个额外的“引导”目标来自动安装 groovy jar 依赖项

      <target name="bootstrap">
        <mkdir dir="${user.home}/.ant/lib"/>
        <get dest="${user.home}/.ant/lib/groovy-all.jar" src="http://search.maven.org/remotecontent?filepath=org/codehaus/groovy/groovy-all/2.2.1/groovy-all-2.2.1.jar"/>
      </target>
    

    【讨论】:

    • 很棒的帖子,虽然它不太管用。引导工作,但 jar 未添加到当前类路径。 taskdef 类 org.codehaus.groovy.ant.Groovy 找不到
    • @spy 我怀疑您使用的 ANT 版本早于 1.6?有关可选任务的安装,请参阅 ANT 文档:ant.apache.org/manual/install.html#optionalTasks
    • 我认为问题是我缺少类路径引用。此外,我从 maven 调用 ant,这带来了额外的类路径挑战。感谢您的洞察力
    • @spy 是的,在 Maven 中使用 ANT 会有所不同。在定义 groovy 任务时,您将需要类路径引用。这可以从 Maven 环境中检索,参见以下文档:maven.apache.org/plugins/maven-antrun-plugin/examples/…
    最近更新 更多