【问题标题】:Code generation using string template使用字符串模板生成代码
【发布时间】:2017-04-02 17:19:43
【问题描述】:

我正在尝试使用字符串模板来生成 Pig/Hadoop 代码。由于我是新手,我自己无法弄清楚。任何帮助将不胜感激。

我有一个如下所示的 LocalDate 列表

List<LocalDate> dates = Arrays.asList("20100101", "20100102").stream().map(d -> LocalDate.parse(d,formatter)).collect(Collectors.toList());

列表可以有 1 个日期或多个日期。

如果列表“日期”包含多个元素,那么我想生成:

SPLIT finalizedEvents INTO splitByDay_20100101 IF dataDate == 20100101,
                  INTO splitByDay_20100102 IF dataDate == 20100102, ....; // for all date in "dates" list
// similarly for all dates
// formatting substitution variable e.g. 2010/01/01 instead of 20100101 is needed
STORE splitByDay_20100101 INTO '/a/b/2010/01/01' USING AvroStorage();
STORE splitByDay_20100102 INTO '/a/b/2010/01/02' USING AvroStorage();

如果列表“日期”只包含一个元素,那么我想生成(假设日期 = [20100101])

splitByDay_20100101 = FOREACH finalizedEvents GENERATE $0..;
STORE splitByDay_20100101 INTO '/a/b/2010/01/01' USING AvroStorage();

到目前为止,我已经做了类似以下的事情,但不知道如何做条件句

ST e = new ST("SPLIT finalizedEvents INTO <[dates]:{ d | IF split_<d> BY daysSinceEpoch == <d>}; separator=\", \">;");
e.add("dates", dates);
System.out.println(e.render());

【问题讨论】:

    标签: stringtemplate stringtemplate-4


    【解决方案1】:

    这是我想出的(下面有详细解释):

    Java 代码:

    List<LocalDate> dates = new ArrayList<>();
    dates.add(LocalDate.parse("20100101", DateTimeFormatter.BASIC_ISO_DATE));
    dates.add(LocalDate.parse("20100201", DateTimeFormatter.BASIC_ISO_DATE));
    
    List<List<Character>> charListList = new ArrayList<>();
    for (LocalDate date : dates) {
        List<Character> charList = new ArrayList<>();
        char[] dateCharArray = date.toString().toCharArray();
        for (char c : dateCharArray) {
            charList.add(c);
        }
        charListList.add(charList);
    }
    
    STGroup dateGroup = new STGroupFile("./src/com/stackoverflow/DateList/dates.stg");
    ST dateTemp = dateGroup.getInstanceOf("writeCode");
    dateTemp.add("formattedDates", charListList);
    dateTemp.add("isSingle", charListList.size() == 1);
    
    System.out.println(dateTemp.render());
    


    字符串模板代码(dates.stg):

    writeCode(formattedDates, isSingle) ::= <<
    <if(isSingle)><writeSingleStuff(formattedDates)>
    <else><writeMultipleStuff(formattedDates)>
    <endif>
    <writeStoreList(formattedDates)>
    >>
    
    
    writeSingleStuff(date)::= "<date:{d|splitByDay_<wordReplaceWSlash(d)> = FOREACH finalizedEvents GENERATE $0..;}>"
    
    writeMultipleStuff(rawDates)::= "SPLIT finalizedEvents <rawDates:{d|INTO splitByDay_<wordReplaceWEmpty(d)> IF dataDate == <wordReplaceWEmpty(d)>}; separator=\", \">;"
    
    writeStoreList(formattedDates)::= "<formattedDates:{d|STORE splitByDay_<wordReplaceWEmpty(d)> INTO '/a/b/<wordReplaceWSlash(d)>' USING AvroStorage();<\n>}>"
    
    
    wordReplaceWSlash(word) ::= "<word:{char|<charReplaceWSlash(char)>}>"
    
    charReplaceWSlash(theChar) ::= <%<charReplaceWSlashMap.(theChar)>%>
    
    charReplaceWSlashMap ::= [
        "-":"/",
        default:{<theChar>}
    ]
    
    
    wordReplaceWEmpty(word) ::= "<word:{char|<charReplaceWEmpty(char)>}>"
    
    charReplaceWEmpty(theChar) ::= <%<charReplaceWEmptyMap.(theChar)>%>
    
    charReplaceWEmptyMap ::= [
        "-":"",
        default:{<theChar>}
    ]
    


    代码的作用:

    Java 代码:

    List<LocalDate> dates = new ArrayList<>();
    dates.add(LocalDate.parse("20100101", DateTimeFormatter.BASIC_ISO_DATE));
    dates.add(LocalDate.parse("20100201", DateTimeFormatter.BASIC_ISO_DATE));
    

    这是一个带有LocalDates 的列表,我们想将其用作模板的输入。我用DateTimeFormatter.BASIC_ISO_DATE 格式化它们,例如20100101 变为 2010-01-01。稍后我们需要这个,因为我们将告诉 StringTemplate 用 / 或空字符串替换 - 以获得我们想要的两种日期格式(我没有找到在第一名)。
    两种不同的方法是:

    • 在 Java 代码中将 - 替换为 /,而不是在 StringTemplate 中。然后,如果我们需要这种日期格式,我们只需要用空字符串替换 /
    • 将年、月和日作为三个不同的变量添加到模板中。然后我们可以连接字符串并在需要时添加/


    List<List<Character>> charListList = new ArrayList<>();
    for (LocalDate date : dates) {
        List<Character> charList = new ArrayList<>();
        char[] dateCharArray = date.toString().toCharArray();
        for (char c : dateCharArray) {
            charList.add(c);
        }
        charListList.add(charList);
    }
    

    我们必须这样做不是很漂亮,但是:
    我们必须有一个日期字符的列表(并且不是一个数组),以便我们可以在 StringTemplate 中“迭代”它。还有no direct way 将char[] 转换为List。最后,我们必须将所有这些列表放在一个列表中,以便我们可以为我们拥有的每个日期生成代码 (charListList)。


    STGroup dateGroup = new STGroupFile("./src/com/stackoverflow/DateList/dates.stg");
    ST dateTemp = dateGroup.getInstanceOf("writeCode");
    dateTemp.add("formattedDates", charListList);
    dateTemp.add("isSingle", charListList.size() == 1);
    
    System.out.println(dateTemp.render());
    

    这里我们用值填充模板。我们必须在 here 告诉 StringTemplate 我们在 charListList 中是否只有一个日期,因为 StringTemplate (by design) 无法这样做。


    字符串模板代码:

    writeCode(formattedDates, isSingle) ::= <<
    <if(isSingle)><writeSingleStuff(formattedDates)>
    <else><writeMultipleStuff(formattedDates)>
    <endif>
    <writeStoreList(formattedDates)>
    >>
    

    这是“根”模板,基本上只是将工作委托给其他模板。它处理一个或多个日期之间的大小写区分。


    writeSingleStuff(date)::= "<date:{d|splitByDay_<wordReplaceWSlash(d)> = FOREACH finalizedEvents GENERATE $0..;}>"
    
    writeMultipleStuff(rawDates)::= "SPLIT finalizedEvents <rawDates:{d|INTO splitByDay_<wordReplaceWEmpty(d)> IF dataDate == <wordReplaceWEmpty(d)>}; separator=\", \">;"
    
    writeStoreList(dates)::= "<dates:{d|STORE splitByDay_<wordReplaceWEmpty(d)> INTO '/a/b/<wordReplaceWSlash(d)>' USING AvroStorage();<\n>}>"
    

    通过这三行代码,我们编写了特定于单个项目、多个项目以及两者共同的代码。
    虽然我们知道在输入writeSingleStuffdate只有一项,但我们必须遍历列表。


    wordReplaceWSlash(word) ::= "<word:{char|<charReplaceWSlash(char)>}>"
    
    charReplaceWSlash(theChar) ::= <%<charReplaceWSlashMap.(theChar)>%>
    
    charReplaceWSlashMap ::= [
        "-":"/",
        default:{<theChar>}
    ]
    
    
    wordReplaceWEmpty(word) ::= "<word:{char|<charReplaceWEmpty(char)>}>"
    
    charReplaceWEmpty(theChar) ::= <%<charReplaceWEmptyMap.(theChar)>%>
    
    charReplaceWEmptyMap ::= [
        "-":"",
        default:{<theChar>}
    ]
    

    这两组模板几乎做同样的事情:将每个“单词”中的每个 - 字符替换为 / 或空字符串。我们使用一个小字典来替换除 - 之外的每个字符。

    【讨论】:

      猜你喜欢
      • 2013-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-14
      • 2017-06-06
      • 1970-01-01
      • 2013-01-26
      • 2023-04-05
      相关资源
      最近更新 更多