Index: lib/src/intl/date_format_field.dart |
diff --git a/lib/src/intl/date_format_field.dart b/lib/src/intl/date_format_field.dart |
index 47a9d7bcc4d85e4328c0c3dca254d941cff9120f..4b8b12e927d289e36f4de9dc8dbb06550b806fc1 100644 |
--- a/lib/src/intl/date_format_field.dart |
+++ b/lib/src/intl/date_format_field.dart |
@@ -39,6 +39,13 @@ abstract class _DateFormatField { |
/** Abstract method for subclasses to implementing parsing for their format.*/ |
void parse(_Stream input, _DateBuilder dateFields); |
+ /** |
+ * Abstract method for subclasses to implementing 'loose' parsing for |
+ * their format, accepting input case-insensitively, and allowing some |
+ * delimiters to be skipped. |
+ */ |
+ void parseLoose(_Stream input, _DateBuilder dateFields); |
+ |
/** Parse a literal field. We just look for the exact input. */ |
void parseLiteral(_Stream input) { |
var found = input.read(width); |
@@ -47,6 +54,20 @@ abstract class _DateFormatField { |
} |
} |
+ /** |
+ * Parse a literal field. We accept either an exact match, or an arbitrary |
+ * amount of whitespace. |
+ */ |
+ void parseLiteralLoose(_Stream input) { |
+ var found = input.peek(width); |
+ if (found == pattern) { |
+ input.read(width); |
+ } |
+ while (!input.atEnd() && input.peek().trim().isEmpty) { |
+ input.read(); |
+ } |
+ } |
+ |
/** Throw a format exception with an error message indicating the position.*/ |
void throwFormatException(_Stream stream) { |
throw new FormatException("Trying to read $this from ${stream.contents} " |
@@ -64,8 +85,11 @@ class _DateFormatLiteralField extends _DateFormatField { |
_DateFormatLiteralField(pattern, parent): super(pattern, parent); |
parse(_Stream input, _DateBuilder dateFields) { |
- return parseLiteral(input); |
+ parseLiteral(input); |
} |
+ |
+ parseLoose(_Stream input, _DateBuilder dateFields) => |
+ parseLiteralLoose(input); |
} |
/** |
@@ -84,9 +108,12 @@ class _DateFormatQuotedField extends _DateFormatField { |
} |
parse(_Stream input, _DateBuilder dateFields) { |
- return parseLiteral(input); |
+ parseLiteral(input); |
} |
+ parseLoose(_Stream input, _DateBuilder dateFields) => |
+ parseLiteralLoose(input); |
+ |
void patchQuotes() { |
if (pattern == "''") { |
pattern = "'"; |
@@ -98,6 +125,110 @@ class _DateFormatQuotedField extends _DateFormatField { |
} |
} |
+/** |
+ * A field that parses "loosely", meaning that we'll accept input that is |
+ * missing delimiters, has upper/lower case mixed up, and might not strictly |
+ * conform to the pattern, e.g. the pattern calls for Sep we might accept |
+ * sep, september, sEPTember. Doesn't affect numeric fields. |
+ */ |
+class _LoosePatternField extends _DateFormatPatternField { |
+ _LoosePatternField(String pattern, parent) : super(pattern, parent); |
+ |
+ /** |
+ * Parse from a list of possibilities, but case-insensitively. |
+ * Assumes that input is lower case. |
+ */ |
+ int parseEnumeratedString(_Stream input, List possibilities) { |
+ var lowercasePossibilities = possibilities |
+ .map((x) => x.toLowerCase()) |
+ .toList(); |
+ try { |
+ return super.parseEnumeratedString(input, lowercasePossibilities); |
+ } on FormatException { |
+ return -1; |
+ } |
+ } |
+ |
+ /** |
+ * Parse a month name, case-insensitively, and set it in [dateFields]. |
+ * Assumes that [input] is lower case. |
+ */ |
+ void parseMonth(input, dateFields) { |
+ if (width <= 2) { |
+ handleNumericField(input, dateFields.setMonth); |
+ return; |
+ } |
+ var possibilities = |
+ [symbols.MONTHS, symbols.SHORTMONTHS]; |
+ for (var monthNames in possibilities) { |
+ var month = parseEnumeratedString(input, monthNames); |
+ if (month != -1) { |
+ dateFields.month = month + 1; |
+ return; |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Parse a standalone day name, case-insensitively. |
+ * Assumes that input is lower case. Doesn't do anything |
+ */ |
+ void parseStandaloneDay(input) { |
+ // This is ignored, but we still have to skip over it the correct amount. |
+ if (width <= 2) { |
+ handleNumericField(input, (x) => x); |
+ return; |
+ } |
+ var possibilities = |
+ [symbols.STANDALONEWEEKDAYS, symbols.STANDALONESHORTWEEKDAYS]; |
+ for (var dayNames in possibilities) { |
+ var day = parseEnumeratedString(input, dayNames); |
+ if (day != -1) { |
+ return; |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Parse a standalone month name, case-insensitively. |
+ * Assumes that input is lower case. Doesn't do anything |
+ */ |
+ void parseStandaloneMonth(input, dateFields) { |
+ if (width <= 2) { |
+ handleNumericField(input, (x) => x); |
+ return; |
+ } |
+ var possibilities = |
+ [symbols.STANDALONEMONTHS, symbols.STANDALONESHORTMONTHS]; |
+ for (var monthNames in possibilities) { |
+ var month = parseEnumeratedString(input, monthNames); |
+ if (month != -1) { |
+ dateFields.month = month + 1; |
+ return; |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * Parse a day of the week name, case-insensitively. |
+ * Assumes that input is lower case. Doesn't do anything |
+ */ |
+ void parseDayOfWeek(_Stream input) { |
+ // This is IGNORED, but we still have to skip over it the correct amount. |
+ if (width <= 2) { |
+ handleNumericField(input, (x) => x); |
+ return; |
+ } |
+ var possibilities = [symbols.WEEKDAYS, symbols.SHORTWEEKDAYS]; |
+ for (var dayNames in possibilities) { |
+ var day = parseEnumeratedString(input, dayNames); |
+ if (day != -1) { |
+ return; |
+ } |
+ } |
+ } |
+} |
+ |
/* |
* Represents a field in the pattern that formats some aspect of the |
* date. Consists primarily of a switch on the particular pattern characters |
@@ -120,6 +251,16 @@ class _DateFormatPatternField extends _DateFormatField { |
parseField(input, dateFields); |
} |
+ |
+ /** |
+ * Parse the date according to our specification and put the result |
+ * into the correct place in dateFields. Allow looser parsing, accepting |
+ * case-insensitive input and skipped delimiters. |
+ */ |
+ void parseLoose(_Stream input, _DateBuilder dateFields) { |
+ new _LoosePatternField(pattern, parent).parse(input, dateFields); |
+ } |
+ |
/** |
* Parse a field representing part of a date pattern. Note that we do not |
* return a value, but rather build up the result in [builder]. |