diff --git a/README.md b/README.md index 7bfe59a..b9c9b6d 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ repositories { ``` groovy dependencies { - compile "ch.poole:OpeningHoursParser:0.16.1" + compile "ch.poole:OpeningHoursParser:0.17.1" } ``` diff --git a/build.gradle b/build.gradle index dd4bb9f..a52a8be 100644 --- a/build.gradle +++ b/build.gradle @@ -16,7 +16,7 @@ apply plugin: 'maven-publish' apply plugin: "jacoco" -version = '0.17.0' +version = '0.17.1' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/src/main/java/ch/poole/openinghoursparser/OpeningHoursParser.jj b/src/main/java/ch/poole/openinghoursparser/OpeningHoursParser.jj index 2570980..a51abe9 100644 --- a/src/main/java/ch/poole/openinghoursparser/OpeningHoursParser.jj +++ b/src/main/java/ch/poole/openinghoursparser/OpeningHoursParser.jj @@ -25,12 +25,15 @@ package ch.poole.openinghoursparser; import java.util.ArrayList; import java.util.Collections; -import java.util.Locale; import java.io.ByteArrayInputStream; public class OpeningHoursParser { +import java.util.Locale; import java.io.ByteArrayInputStream; + +import ch.poole.openinghoursparser.Util; public class OpeningHoursParser { static int TWELVEHOURS = 12*60; boolean strict = false; enum AMPM { AM, PM }; - boolean monthOnly = false; } PARSER_END(OpeningHoursParser) SKIP : { "\r" | "\n" | " " | "\t" + boolean monthOnly = false; } + PARSER_END(OpeningHoursParser) SKIP : { "\r" | "\n" | " " | "\t" | "\u200A" | "\u2009" | "\u00A0" @@ -91,9 +94,9 @@ TOKEN : { < TO : " to " > } /** * match a number between 1 and 5 - */ Token one2five() : { Token n = null; } { LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1 && Integer.parseInt(getToken(1).image) <= 5 }) n = < NUMBER > { return n; } } /** + */ Token one2five() : { Token n = null; } { LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 1, 5) }) n = < NUMBER > { return n; } } /** * match a positive number larger than 1 - */ Token number() : { Token n = null; } { LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1 }) n = < NUMBER > { return n; } } /** + */ Token number() : { Token n = null; } { LOOKAHEAD({ getToken(1).kind == NUMBER && Util.equalsOrMore(getToken(1).image, 1) }) n = < NUMBER > { return n; } } /** * Match a comment. */ String comment() : { StringBuilder builder = new StringBuilder(); } { < QUOTE > ( getChar(builder) )* < ENDQUOTE > { return builder.toString(); } } /** * Match char inside quoted string. @@ -103,7 +106,7 @@ TOKEN : /** * returns a number if between 0 and 24 * uses semantic lookahead - */ Token hours() : { Token h = null; } { LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 0 && Integer.parseInt(getToken(1).image) <= 24 }) h = < NUMBER > { return h; } } + */ Token hours() : { Token h = null; } { LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 0, 24) }) h = < NUMBER > { return h; } } /** * returns the total number of minutes for a time of the form hh:00 or just hh * @@ -166,7 +169,7 @@ AMPM ampm() : /** * returns the total number of minutes for a time of the form hh:00 or just hh with hh up to 48 */ int extendedtime() : { Token h = null; Token m = null; int result = 0; - AMPM ampm = null; } { ( LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 0 && Integer.parseInt(getToken(1).image) <= 48 }) h = < NUMBER > ) ( m = < MINUTES > { + AMPM ampm = null; } { ( LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 0, 48) }) h = < NUMBER > ) ( m = < MINUTES > { if (strict && (m.image.length() < 3 || !m.image.startsWith(":"))) { ParseException pex = new ParseException("Invalid minutes at " + token.next.beginLine + ", column " + token.next.beginColumn); pex.currentToken = token; @@ -336,7 +339,7 @@ WeekDayRange weekday_range() : { String startDay = null; String endDay = nul return mdr; } } - int daynum() : { Token n = null; } { ( LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1 && Integer.parseInt(getToken(1).image) <= 31 }) n = < NUMBER > ) { return Integer.parseInt(n.image); } } + int daynum() : { Token n = null; } { ( LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 1, 31) }) n = < NUMBER > ) { return Integer.parseInt(n.image); } } int year() : { @@ -344,7 +347,7 @@ int year() : } { ( - LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1900}) + LOOKAHEAD({ getToken(1).kind == NUMBER && Util.equalsOrMore(getToken(1).image, 1900)}) n = < NUMBER > ) { @@ -486,7 +489,7 @@ int year() : return result; } ) -} int weeknum() : { Token n = null; } { ( LOOKAHEAD({ getToken(1).kind == NUMBER && Integer.parseInt(getToken(1).image) >= 1 && Integer.parseInt(getToken(1).image) <= 54 }) n = < NUMBER > ) { return Integer.parseInt(n.image); } } WeekRange week_range() : { WeekRange wr = new WeekRange(); Token w = null; Token w1 = null; +} int weeknum() : { Token n = null; } { ( LOOKAHEAD({ getToken(1).kind == NUMBER && Util.between(getToken(1).image, 1, 54) }) n = < NUMBER > ) { return Integer.parseInt(n.image); } } WeekRange week_range() : { WeekRange wr = new WeekRange(); Token w = null; Token w1 = null; Token to = null; } { wr.startWeek = weeknum() ( ( < HYPHEN > | (to = < TO >) ) ( diff --git a/src/main/java/ch/poole/openinghoursparser/Util.java b/src/main/java/ch/poole/openinghoursparser/Util.java index 5f99eb6..9984b70 100644 --- a/src/main/java/ch/poole/openinghoursparser/Util.java +++ b/src/main/java/ch/poole/openinghoursparser/Util.java @@ -79,7 +79,7 @@ public static List> getMergeableRules(List rules) { public static String rulesToOpeningHoursString(@NotNull List rules) { return rulesToOpeningHoursString(rules, false); } - + /** * Generate an OH string from rules * @@ -180,4 +180,37 @@ static > List copyList(List l) { } return r; } + + /** + * Make a safe comparison catching parse errors + * + * @param token the current token + * @param lower lower bounds + * @return true if greater or equals to limit and is an int + */ + static boolean equalsOrMore(@NotNull String token, int lower) { + try { + int temp = Integer.parseInt(token); + return temp >= lower; + } catch (NumberFormatException nfe) { + return false; + } + } + + /** + * Make a safe comparison catching parse errors + * + * @param token the current token + * @param lower lower bounds + * @param upper upper bounds + * @return true if in bounds and is an int + */ + static boolean between(@NotNull String token, int lower, int upper) { + try { + int temp = Integer.parseInt(token); + return temp >= lower && temp <= upper; + } catch (NumberFormatException nfe) { + return false; + } + } } diff --git a/test-data/oh.txt-result b/test-data/oh.txt-result index b3fd73d..78d2ccb 100644 --- a/test-data/oh.txt-result +++ b/test-data/oh.txt-result @@ -8989,7 +8989,7 @@ 1 1 1 -2 +1 1 1 0 02:00-09:00 @@ -11083,7 +11083,7 @@ 1 0 08:00-10:30,11:00-14:30; Fr off 0 08:00-21:00 -2 +1 0 08:00-10:00 0 08:00-10:00,04:00-19:00 1 diff --git a/test-data/oh.txt-result-strict b/test-data/oh.txt-result-strict index dee129a..b56a2eb 100644 --- a/test-data/oh.txt-result-strict +++ b/test-data/oh.txt-result-strict @@ -8989,7 +8989,7 @@ 1 1 1 -2 +1 1 1 1 @@ -11083,7 +11083,7 @@ 1 1 1 -2 +1 1 1 1