private boolean expect(String source, ParsePosition pos, char ch) { int x = pos.getIndex(); boolean r = x < source.length() && source.charAt(x) == ch; if (r) pos.setIndex(x + 1); else pos.setErrorIndex(x); return r; }
/** * Parses a {@code Number} from the specified string using the rules of this number format. * * @param string the string to parse. * @return the {@code Number} resulting from the parsing. * @throws ParseException if an error occurs during parsing. */ public Number parse(String string) throws ParseException { ParsePosition pos = new ParsePosition(0); Number number = parse(string, pos); if (pos.getIndex() == 0) { throw new ParseException("Unparseable number: \"" + string + "\"", pos.getErrorIndex()); } return number; }
private int parseNumber(int max, String string, int offset, int field, int skew) { ParsePosition position = new ParsePosition(offset); Number result = parseNumber(max, string, position); if (result == null) { return -position.getErrorIndex() - 1; } calendar.set(field, result.intValue() + skew); return position.getIndex(); }
/** Does the parse-work without the mandatory-check */ private String parse2(String external) throws FmtParseException { // trim blanks on both sides if (external == null) return ""; external = external.trim(); if (external.length() == 0) return ""; else { ParsePosition pp = new ParsePosition(0); Date date = null; date = dateFormat_.parse(external, pp); if (date == null || (pp.getIndex() != external.length() && pp.getIndex() > 0)) { throw new FmtParseException("ATSSyntax", getSampleTS()); } return TimeStampUtil.date2Internal(date); } }
protected void load() throws IOException { BufferedReader is = new BufferedReader(new FileReader("ReminderService.txt")); SimpleDateFormat formatter = new SimpleDateFormat("yyyy MM dd hh mm"); String aLine; while ((aLine = is.readLine()) != null) { ParsePosition pp = new ParsePosition(0); Date date = formatter.parse(aLine, pp); if (date == null) { message("Invalid date in " + aLine); continue; } String mesg = aLine.substring(pp.getIndex()); l.add(new Item(date, mesg)); } }
public void test(TestHarness harness) { ParsePosition pp = new ParsePosition(69); harness.check(pp.getIndex(), 69, "getIndex() post-create"); pp.setIndex(666); harness.check(pp.getIndex(), 666, "set/getIndex()"); harness.check(pp.getErrorIndex(), -1, "getErrorIndex() no error"); pp.setErrorIndex(65536); harness.check(pp.getErrorIndex(), 65536, "set/getErrorIndex()"); harness.debug(pp.toString()); }
@Override public Date parse(String i, ParsePosition p) { /* delegate to SimpleDateFormat for easy stuff */ Date d = super.parse(i, p); int milliIndex = p.getIndex(); /* worry about the milliseconds ourselves */ if (null != d && -1 == p.getErrorIndex() && milliIndex + 1 < i.length() && '.' == i.charAt(milliIndex)) { p.setIndex(++milliIndex); // NOTE: ++ to chomp '.' Number millis = millisParser.parse(i, p); if (-1 == p.getErrorIndex()) { int endIndex = p.getIndex(); d = new Date( d.getTime() + (long) (millis.doubleValue() * Math.pow(10, (3 - endIndex + milliIndex)))); } } return d; }
private Number parseNumber(int max, String string, ParsePosition position) { int length = string.length(); int index = position.getIndex(); if (max > 0 && max < length - index) { length = index + max; } while (index < length && (string.charAt(index) == ' ' || string.charAt(index) == '\t')) { ++index; } if (max == 0) { position.setIndex(index); Number n = numberFormat.parse(string, position); // In RTL locales, NumberFormat might have parsed "2012-" in an ISO date as the // negative number -2012. // Ideally, we wouldn't have this broken API that exposes a NumberFormat and expects // us to use it. The next best thing would be a way to ask the NumberFormat to parse // positive numbers only, but icu4c supports negative (BCE) years. The best we can do // is try to recognize when icu4c has done this, and undo it. if (n != null && n.longValue() < 0) { if (numberFormat instanceof DecimalFormat) { DecimalFormat df = (DecimalFormat) numberFormat; char lastChar = string.charAt(position.getIndex() - 1); char minusSign = df.getDecimalFormatSymbols().getMinusSign(); if (lastChar == minusSign) { n = Long.valueOf(-n.longValue()); // Make the value positive. position.setIndex(position.getIndex() - 1); // Spit out the negative sign. } } } return n; } int result = 0; int digit; while (index < length && (digit = Character.digit(string.charAt(index), 10)) != -1) { result = result * 10 + digit; ++index; } if (index == position.getIndex()) { position.setErrorIndex(index); return null; } position.setIndex(index); return Integer.valueOf(result); }
/** * This method parses the specified string into a date. * * @param dateStr The date string to parse. * @param pos The input and output parse position * @return The parsed date, or <code>null</code> if the string cannot be parsed. */ public Date parse(String dateStr, ParsePosition pos) { int fmt_index = 0; int fmt_max = pattern.length(); calendar.clear(); boolean saw_timezone = false; int quote_start = -1; boolean is2DigitYear = false; try { for (; fmt_index < fmt_max; ++fmt_index) { char ch = pattern.charAt(fmt_index); if (ch == '\'') { int index = pos.getIndex(); if (fmt_index < fmt_max - 1 && pattern.charAt(fmt_index + 1) == '\'') { if (!expect(dateStr, pos, ch)) return null; ++fmt_index; } else quote_start = quote_start < 0 ? fmt_index : -1; continue; } if (quote_start != -1 || ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'))) { if (!expect(dateStr, pos, ch)) return null; continue; } // We've arrived at a potential pattern character in the // pattern. int fmt_count = 1; while (++fmt_index < fmt_max && pattern.charAt(fmt_index) == ch) { ++fmt_count; } // We might need to limit the number of digits to parse in // some cases. We look to the next pattern character to // decide. boolean limit_digits = false; if (fmt_index < fmt_max && standardChars.indexOf(pattern.charAt(fmt_index)) >= 0) limit_digits = true; --fmt_index; // We can handle most fields automatically: most either are // numeric or are looked up in a string vector. In some cases // we need an offset. When numeric, `offset' is added to the // resulting value. When doing a string lookup, offset is the // initial index into the string array. int calendar_field; boolean is_numeric = true; int offset = 0; boolean maybe2DigitYear = false; boolean oneBasedHour = false; boolean oneBasedHourOfDay = false; Integer simpleOffset; String[] set1 = null; String[] set2 = null; switch (ch) { case 'd': calendar_field = Calendar.DATE; break; case 'D': calendar_field = Calendar.DAY_OF_YEAR; break; case 'F': calendar_field = Calendar.DAY_OF_WEEK_IN_MONTH; break; case 'E': is_numeric = false; offset = 1; calendar_field = Calendar.DAY_OF_WEEK; set1 = formatData.getWeekdays(); set2 = formatData.getShortWeekdays(); break; case 'w': calendar_field = Calendar.WEEK_OF_YEAR; break; case 'W': calendar_field = Calendar.WEEK_OF_MONTH; break; case 'M': calendar_field = Calendar.MONTH; if (fmt_count <= 2) offset = -1; else { is_numeric = false; set1 = formatData.getMonths(); set2 = formatData.getShortMonths(); } break; case 'y': calendar_field = Calendar.YEAR; if (fmt_count <= 2) maybe2DigitYear = true; break; case 'K': calendar_field = Calendar.HOUR; break; case 'h': calendar_field = Calendar.HOUR; oneBasedHour = true; break; case 'H': calendar_field = Calendar.HOUR_OF_DAY; break; case 'k': calendar_field = Calendar.HOUR_OF_DAY; oneBasedHourOfDay = true; break; case 'm': calendar_field = Calendar.MINUTE; break; case 's': calendar_field = Calendar.SECOND; break; case 'S': calendar_field = Calendar.MILLISECOND; break; case 'a': is_numeric = false; calendar_field = Calendar.AM_PM; set1 = formatData.getAmPmStrings(); break; case 'z': case 'Z': // We need a special case for the timezone, because it // uses a different data structure than the other cases. is_numeric = false; calendar_field = Calendar.ZONE_OFFSET; String[][] zoneStrings = formatData.getZoneStrings(); int zoneCount = zoneStrings.length; int index = pos.getIndex(); boolean found_zone = false; simpleOffset = computeOffset(dateStr.substring(index)); if (simpleOffset != null) { found_zone = true; saw_timezone = true; calendar.set(Calendar.DST_OFFSET, 0); offset = simpleOffset.intValue(); } else { for (int j = 0; j < zoneCount; j++) { String[] strings = zoneStrings[j]; int k; for (k = 0; k < strings.length; ++k) { if (dateStr.startsWith(strings[k], index)) break; } if (k != strings.length) { found_zone = true; saw_timezone = true; TimeZone tz = TimeZone.getTimeZone(strings[0]); // Check if it's a DST zone or ordinary if (k == 3 || k == 4) calendar.set(Calendar.DST_OFFSET, tz.getDSTSavings()); else calendar.set(Calendar.DST_OFFSET, 0); offset = tz.getRawOffset(); pos.setIndex(index + strings[k].length()); break; } } } if (!found_zone) { pos.setErrorIndex(pos.getIndex()); return null; } break; default: pos.setErrorIndex(pos.getIndex()); return null; } // Compute the value we should assign to the field. int value; int index = -1; if (is_numeric) { numberFormat.setMinimumIntegerDigits(fmt_count); if (limit_digits) numberFormat.setMaximumIntegerDigits(fmt_count); if (maybe2DigitYear) index = pos.getIndex(); Number n = numberFormat.parse(dateStr, pos); if (pos == null || !(n instanceof Long)) return null; value = n.intValue() + offset; } else if (set1 != null) { index = pos.getIndex(); int i; boolean found = false; for (i = offset; i < set1.length; ++i) { if (set1[i] != null) if (dateStr.toUpperCase().startsWith(set1[i].toUpperCase(), index)) { found = true; pos.setIndex(index + set1[i].length()); break; } } if (!found && set2 != null) { for (i = offset; i < set2.length; ++i) { if (set2[i] != null) if (dateStr.toUpperCase().startsWith(set2[i].toUpperCase(), index)) { found = true; pos.setIndex(index + set2[i].length()); break; } } } if (!found) { pos.setErrorIndex(index); return null; } value = i; } else value = offset; if (maybe2DigitYear) { // Parse into default century if the numeric year string has // exactly 2 digits. int digit_count = pos.getIndex() - index; if (digit_count == 2) { is2DigitYear = true; value += defaultCentury; } } // Calendar uses 0-based hours. // I.e. 00:00 AM is midnight, not 12 AM or 24:00 if (oneBasedHour && value == 12) value = 0; if (oneBasedHourOfDay && value == 24) value = 0; // Assign the value and move on. calendar.set(calendar_field, value); } if (is2DigitYear) { // Apply the 80-20 heuristic to dermine the full year based on // defaultCenturyStart. int year = calendar.get(Calendar.YEAR); if (calendar.getTime().compareTo(defaultCenturyStart) < 0) calendar.set(Calendar.YEAR, year + 100); } if (!saw_timezone) { // Use the real rules to determine whether or not this // particular time is in daylight savings. calendar.clear(Calendar.DST_OFFSET); calendar.clear(Calendar.ZONE_OFFSET); } return calendar.getTime(); } catch (IllegalArgumentException x) { pos.setErrorIndex(pos.getIndex()); return null; } }
/** * Parses a date from the specified string starting at the index specified by {@code position}. If * the string is successfully parsed then the index of the {@code ParsePosition} is updated to the * index following the parsed text. On error, the index is unchanged and the error index of {@code * ParsePosition} is set to the index where the error occurred. * * @param string the string to parse using the pattern of this simple date format. * @param position input/output parameter, specifies the start index in {@code string} from where * to start parsing. If parsing is successful, it is updated with the index following the * parsed text; on error, the index is unchanged and the error index is set to the index where * the error occurred. * @return the date resulting from the parse, or {@code null} if there is an error. * @throws IllegalArgumentException if there are invalid characters in the pattern. */ @Override public Date parse(String string, ParsePosition position) { // Harmony delegates to ICU's SimpleDateFormat, we implement it directly boolean quote = false; int next, last = -1, count = 0, offset = position.getIndex(); int length = string.length(); calendar.clear(); TimeZone zone = calendar.getTimeZone(); final int patternLength = pattern.length(); for (int i = 0; i < patternLength; i++) { next = pattern.charAt(i); if (next == '\'') { if (count > 0) { if ((offset = parse(string, offset, (char) last, count)) < 0) { return error(position, -offset - 1, zone); } count = 0; } if (last == next) { if (offset >= length || string.charAt(offset) != '\'') { return error(position, offset, zone); } offset++; last = -1; } else { last = next; } quote = !quote; continue; } if (!quote && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) { if (last == next) { count++; } else { if (count > 0) { if ((offset = parse(string, offset, (char) last, -count)) < 0) { return error(position, -offset - 1, zone); } } last = next; count = 1; } } else { if (count > 0) { if ((offset = parse(string, offset, (char) last, count)) < 0) { return error(position, -offset - 1, zone); } count = 0; } last = -1; if (offset >= length || string.charAt(offset) != next) { return error(position, offset, zone); } offset++; } } if (count > 0) { if ((offset = parse(string, offset, (char) last, count)) < 0) { return error(position, -offset - 1, zone); } } Date date; try { date = calendar.getTime(); } catch (IllegalArgumentException e) { return error(position, offset, zone); } position.setIndex(offset); calendar.setTimeZone(zone); return date; }
private int parse(String string, int offset, char format, int count) { int index = PATTERN_CHARS.indexOf(format); if (index == -1) { throw new IllegalArgumentException("Unknown pattern character '" + format + "'"); } int field = -1; // TODO: what's 'absolute' for? when is 'count' negative, and why? int absolute = 0; if (count < 0) { count = -count; absolute = count; } switch (index) { case ERA_FIELD: return parseText(string, offset, formatData.eras, Calendar.ERA); case YEAR_FIELD: if (count >= 3) { field = Calendar.YEAR; } else { ParsePosition position = new ParsePosition(offset); Number result = parseNumber(absolute, string, position); if (result == null) { return -position.getErrorIndex() - 1; } int year = result.intValue(); // A two digit year must be exactly two digits, i.e. 01 if ((position.getIndex() - offset) == 2 && year >= 0) { year += creationYear / 100 * 100; if (year < creationYear) { year += 100; } } calendar.set(Calendar.YEAR, year); return position.getIndex(); } break; case STAND_ALONE_MONTH_FIELD: // 'L' return parseMonth(string, offset, count, absolute, true); case MONTH_FIELD: // 'M' return parseMonth(string, offset, count, absolute, false); case DATE_FIELD: field = Calendar.DATE; break; case HOUR_OF_DAY1_FIELD: // 'k' ParsePosition position = new ParsePosition(offset); Number result = parseNumber(absolute, string, position); if (result == null) { return -position.getErrorIndex() - 1; } int hour = result.intValue(); if (hour == 24) { hour = 0; } calendar.set(Calendar.HOUR_OF_DAY, hour); return position.getIndex(); case HOUR_OF_DAY0_FIELD: // 'H' field = Calendar.HOUR_OF_DAY; break; case MINUTE_FIELD: field = Calendar.MINUTE; break; case SECOND_FIELD: field = Calendar.SECOND; break; case MILLISECOND_FIELD: field = Calendar.MILLISECOND; break; case STAND_ALONE_DAY_OF_WEEK_FIELD: return parseDayOfWeek(string, offset, true); case DAY_OF_WEEK_FIELD: return parseDayOfWeek(string, offset, false); case DAY_OF_YEAR_FIELD: field = Calendar.DAY_OF_YEAR; break; case DAY_OF_WEEK_IN_MONTH_FIELD: field = Calendar.DAY_OF_WEEK_IN_MONTH; break; case WEEK_OF_YEAR_FIELD: field = Calendar.WEEK_OF_YEAR; break; case WEEK_OF_MONTH_FIELD: field = Calendar.WEEK_OF_MONTH; break; case AM_PM_FIELD: return parseText(string, offset, formatData.ampms, Calendar.AM_PM); case HOUR1_FIELD: // 'h' position = new ParsePosition(offset); result = parseNumber(absolute, string, position); if (result == null) { return -position.getErrorIndex() - 1; } hour = result.intValue(); if (hour == 12) { hour = 0; } calendar.set(Calendar.HOUR, hour); return position.getIndex(); case HOUR0_FIELD: // 'K' field = Calendar.HOUR; break; case TIMEZONE_FIELD: // 'z' return parseTimeZone(string, offset); case RFC_822_TIMEZONE_FIELD: // 'Z' return parseTimeZone(string, offset); } if (field != -1) { return parseNumber(absolute, string, offset, field, 0); } return offset; }
private Date error(ParsePosition position, int offset, TimeZone zone) { position.setErrorIndex(offset); calendar.setTimeZone(zone); return null; }
private int parseTimeZone(String string, int offset) { boolean foundGMT = string.regionMatches(offset, "GMT", 0, 3); if (foundGMT) { offset += 3; } char sign; if (offset < string.length() && ((sign = string.charAt(offset)) == '+' || sign == '-')) { ParsePosition position = new ParsePosition(offset + 1); Number result = numberFormat.parse(string, position); if (result == null) { return -position.getErrorIndex() - 1; } int hour = result.intValue(); int raw = hour * 3600000; int index = position.getIndex(); if (index < string.length() && string.charAt(index) == ':') { position.setIndex(index + 1); result = numberFormat.parse(string, position); if (result == null) { return -position.getErrorIndex() - 1; } int minute = result.intValue(); raw += minute * 60000; } else if (hour >= 24) { raw = (hour / 100 * 3600000) + (hour % 100 * 60000); } if (sign == '-') { raw = -raw; } calendar.setTimeZone(new SimpleTimeZone(raw, "")); return position.getIndex(); } if (foundGMT) { calendar.setTimeZone(TimeZone.getTimeZone("GMT")); return offset; } for (String[] row : formatData.internalZoneStrings()) { for (int i = TimeZoneNames.LONG_NAME; i < TimeZoneNames.NAME_COUNT; ++i) { if (row[i] == null) { // If icu4c doesn't have a name, our array contains a null. Normally we'd // work out the correct GMT offset, but we already handled parsing GMT offsets continue; } if (string.regionMatches(true, offset, row[i], 0, row[i].length())) { TimeZone zone = TimeZone.getTimeZone(row[TimeZoneNames.OLSON_NAME]); if (zone == null) { return -offset - 1; } int raw = zone.getRawOffset(); if (i == TimeZoneNames.LONG_NAME_DST || i == TimeZoneNames.SHORT_NAME_DST) { // Not all time zones use a one-hour difference, so we need to query // the TimeZone. (Australia/Lord_Howe is the usual example of this.) int dstSavings = zone.getDSTSavings(); // One problem with TimeZone.getDSTSavings is that it will return 0 if the // time zone has stopped using DST, even if we're parsing a date from // the past. In that case, assume the default. if (dstSavings == 0) { // TODO: we should change this to use TimeZone.getOffset(long), // but that requires the complete date to be parsed first. dstSavings = 3600000; } raw += dstSavings; } calendar.setTimeZone(new SimpleTimeZone(raw, "")); return offset + row[i].length(); } } } return -offset - 1; }
public Object[] parse(String sourceStr) throws ParseException { ParsePosition pp = new ParsePosition(0); Object[] r = parse(sourceStr, pp); if (r == null) throw new ParseException("couldn't parse string", pp.getErrorIndex()); return r; }
/** * Parse a string <code>sourceStr</code> against the pattern specified to the MessageFormat * constructor. * * @param sourceStr the string to be parsed. * @param pos the current parse position (and eventually the error position). * @return the array of parsed objects sorted according to their argument number in the pattern. */ public Object[] parse(String sourceStr, ParsePosition pos) { // Check initial text. int index = pos.getIndex(); if (!sourceStr.startsWith(leader, index)) { pos.setErrorIndex(index); return null; } index += leader.length(); Vector results = new Vector(elements.length, 1); // Now check each format. for (int i = 0; i < elements.length; ++i) { Format formatter = null; if (elements[i].setFormat != null) formatter = elements[i].setFormat; else if (elements[i].format != null) formatter = elements[i].format; Object value = null; if (formatter instanceof ChoiceFormat) { // We must special-case a ChoiceFormat because it might // have recursive formatting. ChoiceFormat cf = (ChoiceFormat) formatter; String[] formats = (String[]) cf.getFormats(); double[] limits = (double[]) cf.getLimits(); MessageFormat subfmt = new MessageFormat(); subfmt.setLocale(locale); ParsePosition subpos = new ParsePosition(index); int j; for (j = 0; value == null && j < limits.length; ++j) { subfmt.applyPattern(formats[j]); subpos.setIndex(index); value = subfmt.parse(sourceStr, subpos); } if (value != null) { index = subpos.getIndex(); value = new Double(limits[j]); } } else if (formatter != null) { pos.setIndex(index); value = formatter.parseObject(sourceStr, pos); if (value != null) index = pos.getIndex(); } else { // We have a String format. This can lose in a number // of ways, but we give it a shot. int next_index = sourceStr.indexOf(elements[i].trailer, index); if (next_index == -1) { pos.setErrorIndex(index); return null; } value = sourceStr.substring(index, next_index); index = next_index; } if (value == null || !sourceStr.startsWith(elements[i].trailer, index)) { pos.setErrorIndex(index); return null; } if (elements[i].argNumber >= results.size()) results.setSize(elements[i].argNumber + 1); results.setElementAt(value, elements[i].argNumber); index += elements[i].trailer.length(); } Object[] r = new Object[results.size()]; results.copyInto(r); return r; }