Вот что у меня получилось (подробное объяснение ниже):
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());
Код StringTemplate (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 заменить -
либо на /
, либо на пустую строку, чтобы получить два типа форматов даты, которые нам нужны (и я не нашел средство форматирования, которое изначально получает 2010/01/01
).
Два разных подхода:
- Замените
-
на /
в коде 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);
}
Это не очень красиво, но:
У нас должен быть список (а не массив) символов даты, чтобы мы могли "перебирать" его. в шаблоне строки. И нет прямого способа преобразовать char[] в список. В конце концов, нам нужно собрать все эти списки в один список, чтобы мы могли генерировать код для каждой имеющейся у нас даты (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());
Здесь мы заполняем шаблон значениями. Мы должны сообщить StringTemplate здесь, есть ли у нас ровно одна дата в нашем charListList
, потому что StringTemplate (преднамеренно) не может этого сделать.
StringTemplateCode:
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>}>"
С помощью этих трех строк мы пишем код, специфичный для одного элемента, для нескольких элементов, и код, который является общим.
Хотя мы знаем, что date
имеет только один элемент, когда мы вводим writeSingleStuff
, мы должны перебрать список.
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>}
]
Это две группы шаблонов, которые почти делают одно и то же: заменяют каждый символ -
в каждом «слове» либо на /
, либо на пустую строку. Для этого мы используем небольшой словарь, который заменяет каждый символ, кроме -
, самим собой.
person
Colophonius
schedule
05.02.2017