Java 如何使用ANTLR v3构建日期/小时语法?
我想用Antlr解析一串法国日期 我有三种类型的约会:Java 如何使用ANTLR v3构建日期/小时语法?,java,antlr,antlr3,Java,Antlr,Antlr3,我想用Antlr解析一串法国日期 我有三种类型的约会: 日期:2004年10月3日(小时/分钟为午夜) 日期\时间:12小时(以当前日期填写日、月、年) 完成日期:2004年10月3日12小时。您可以看到date\u complete:date\u day date\u hour 我要分析的文档只是一个由date\u day、date\u time和date\u complete组成的链(没有分隔符) 下面是我想要解析的字符串的示例 3 Octobre 2005 12h 13h 5 Octo
- 日期:2004年10月3日(小时/分钟为午夜)
- 日期\时间:12小时(以当前日期填写日、月、年)
- 完成日期:2004年10月3日12小时。您可以看到
date\u complete:date\u day date\u hour
date\u day
、date\u time
和date\u complete
组成的链(没有分隔符)
下面是我想要解析的字符串的示例
3 Octobre 2005 12h 13h 5 Octobre 2004 3 Septembre 2005 11h
Expected : date_complete date_time date_day date_complete
12h
Expected : date_time
3 Octobre 2005 5 Octobre 2004 12h 13h 3 Septembre 2005 11h
Expected : date_day date_complete date_time date_complete
**// NEW REQUIREMENTS**
3 Octobre 2005
Expected : date_day
3 Octobre
Expected : date_day
3
Expected : date_day
我尝试了很多东西,Antlr v3总是说我的语法模棱两可:
warning(200): /meleo.dates/src/Grammar.g:25:48:
Decision can match input such as "{FRI, MON..TUE, WED} TWO_DIGITS DECEMBER FOUR_DIGITS {FRI..HOURG, MON..WED}" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
|---> date_day (date_day | date_complete | date_hour)+
写那种语法的正确方法是什么
语法如下:
grammar MeleoDates;
options {
language = Java;
}
@header {
package meleo.data.dates ;
import rainstudios.meleo.crawler.data.Dates ;
import rainstudios.meleo.crawler.data.EventDate ;
}
@lexer::header {
package meleo.data.dates ;
import rainstudios.meleo.crawler.data.EventDate ;
}
input returns [Dates dates]
@init {Dates r = new Dates() ; } :
( date
{r.addDay($date.date);}
DATE_SEP?)+
EOF
{$dates = r ;}
;
date returns [EventDate date] :
(date_complete)=> date_complete
{$date = $date_complete.date;}
| date_day
{$date = $date_day.date;}
| date_time
{$date = $date_time.date;}
;
date_complete returns [EventDate date]
@init {EventDateBuilder builder = new EventDateBuilder() ; } :
day=date_day
{builder.addDay($day.date);}
HOUR_SEP?
time=date_time
{builder.addTime($time.date);}
{$date = builder.toDate();}
;
date_day returns [EventDate date]
@init {EventDateBuilder builder = new EventDateBuilder() ; } :
(
dayOfWeek=(
MON
| TUE
| WED
| THU
| FRI
| SAT
| SUN
)?
(day=INT)=> INT
{builder.addDay($day.text);}
( m=ID
{builder.addMonth($m.text);}
year=INT ?
{builder.addMonth($year.text);}
)?
)
{$date = builder.toDate();}
;
date_time returns [EventDate date]
@init {EventDateBuilder builder = new EventDateBuilder() ; } :
TIME
{builder.addTime($TIME.text);}
{$date = builder.toDate();}
;
month : DECEMBER | JANUARY ;
MON
: 'lundi'
| 'lun'
;
TUE
: 'mardi'
| 'mar'
;
WED
: 'mercredi'
| 'mer'
;
THU
: 'jeudi'
| 'jeu'
;
FRI
: 'venredi'
| 'ven'
;
SAT
: 'samedi'
| 'sam'
;
SUN
: 'dimanche'
| 'dim'
;
DECEMBER : 'dec' | 'decembre' ;
JANUARY : 'jan' | 'janvier' ;
DATE_SEP : 'et'| ',' | '-';
HOUR_SEP : 'à' | 'a' ;
INT : ('0'..'9')+;
TIME_SEP : ':' | 'h' ;
TIME : INT TIME_SEP INT?;
ID : ('a'..'z'|'A'..'Z')+;
WS : (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel = HIDDEN;};
**编辑:添加了新的要求(日期可选的月份和年份)**我认为使用ANTLR不会带来任何好处。相反,您可以使用一些附加工作来检查拖尾小时(即“h”)标记,以实现以下目标: 一揽子问题
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Locale;
public class FrenchDateParser {
private static SimpleDateFormat date_complete = new SimpleDateFormat("d MMMM yyyy h", Locale.FRENCH);
private static SimpleDateFormat date_day = new SimpleDateFormat("d MMMM yyyy", Locale.FRENCH);
private static SimpleDateFormat date_time = new SimpleDateFormat("h", Locale.FRENCH);
private static String parse(String input) {
ParsePosition parsePosition = new ParsePosition(0);
StringBuilder stringBuilder = new StringBuilder();
int inputSize = input.length();
while (parsePosition.getIndex() < inputSize) {
int startingParsePositionIndex = parsePosition.getIndex();
if (date_complete.parse(input, parsePosition) != null) {
if (input.charAt(parsePosition.getIndex()) == 'h') {
stringBuilder.append("date_complete ");
parsePosition.setIndex(parsePosition.getIndex() + 1);
continue;
}
parsePosition.setIndex(startingParsePositionIndex);
}
if (date_day.parse(input, parsePosition) != null) {
stringBuilder.append("date_day ");
continue;
}
if (date_time.parse(input, parsePosition) != null) {
if (input.charAt(parsePosition.getIndex()) == 'h') {
stringBuilder.append("date_time ");
parsePosition.setIndex(parsePosition.getIndex() + 1);
continue;
}
parsePosition.setIndex(startingParsePositionIndex);
}
throw new IllegalArgumentException("Unable to parse input [" + input + "]");
}
return stringBuilder.toString().trim();
}
public static void main(String... args) throws ParseException {
String[] inputs = {"3 Octobre 2005 12h 13h 5 Octobre 2004 3 Septembre 2005 11h", "12h",
"3 Octobre 2005 5 Octobre 2004 12h 13h 3 Septembre 2005 11h"};
String[] expecteds = {"date_complete date_time date_day date_complete", "date_time",
"date_day date_complete date_time date_complete"};
for (int i = 0; i < inputs.length; i++) {
String actual = parse(inputs[i]);
System.out.println(expecteds[i].equals(actual));
}
}
}
import java.text.ParseException;
导入java.text.ParsePosition;
导入java.text.simpleDataFormat;
导入java.util.Locale;
公共类FrenchDateParser{
私有静态SimpleDataFormat date_complete=新SimpleDataFormat(“d MMMM yyy h”,Locale.FRENCH);
私有静态SimpleDataFormat date\u day=新SimpleDataFormat(“d MMMM yyyy”,Locale.FRENCH);
私有静态SimpleDataFormat日期\时间=新SimpleDataFormat(“h”,Locale.FRENCH);
私有静态字符串解析(字符串输入){
ParsePosition ParsePosition=新的ParsePosition(0);
StringBuilder StringBuilder=新的StringBuilder();
int inputSize=input.length();
while(parsePosition.getIndex()
考虑使用语法谓词:
input : date+;
date : (date_complete) => date_complete
| date_day
| date_time
;
实际上,这告诉ANTLR在尝试匹配它通常找到的任何内容之前,先尝试一个日期_complete
(这可能不是一个技术上准确的描述,但你知道了)。如果没有这一点,date
规则可以使用相同的输入匹配多个选项,而ANTLR(无论如何,是v3)无法解决这一问题
以下是完整的测试语法:
grammar AmbiguousDates;
input : date+ EOF;
date : (date_complete)=> date_complete
{System.out.println("date_complete: " + $date_complete.str);}
| date_day
{System.out.println("date_day: " + $date_day.str);}
| date_time
{System.out.println("date_time: " + $date_time.str);}
;
date_complete returns [String str]
: date_day date_time
{$str = String.format("\%s \%s", $date_day.str, $date_time.str);}
;
date_day returns [String str]
: day=INT ID year=INT
{$str = String.format("\%s \%s \%s", $day.text, $ID.text, $year.text);}
;
date_time returns [String str]
: TIME
{$str = $TIME.text;}
;
INT : ('0'..'9')+;
TIME : INT 'h';
ID : ('a'..'z'|'A'..'Z')+;
WS : (' '|'\t'|'\f'|'\r'|'\n')+ {skip();};
输入
输出
你可以在这里发布你的语法吗?现在,根据@tenterhook suggestionI的语法,为了这个问题,我简化了日期和时间。使用ANTLR仍然不能确保有效的日期,例如闰年,并且会生成你想要的默认值(例如,“日期”小时/分钟是午夜)因此,我们仍然没有看到ANTLR通过Java的内置解析器提供了什么。使用Java内置的日期解析器可以同时为您进行解析和验证。下一步是添加间隔:“从12h30到15h45”和许多其他内容,比如解析少量自然语言“午夜,中午,明天”。一个合适的解析器看起来是可行的。现在,我想让月份和年份成为可选的<代码>日期返回[String str]:day=INT ID?年份=整数但是我又犯了一次可怕的模棱两可的语法错误。有什么想法吗?@nameiscall
date\u day
不知道INT
的意思是“date\u day=day year”还是“date\u day=day date\u day=day”。尝试制定词法规则,如匹配一个或两个数字的DAY
,匹配四个数字的YEAR
,然后将date\u DAY
更改为DAY ID?年份?
如果遇到问题,开始新问题可能会更容易。
3 Octobre 2005 12h 13h 5 Octobre 2004 3 Septembre 2005 11h
date_complete: 3 Octobre 2005 12h
date_time: 13h
date_day: 5 Octobre 2004
date_complete: 3 Septembre 2005 11h