All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.xfa.ut.PictureFmt Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright 2005 Adobe Systems Incorporated All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of
 * Adobe Systems Incorporated and its suppliers, if any. The intellectual and
 * technical concepts contained herein are proprietary to Adobe Systems
 * Incorporated and its suppliers and may be covered by U.S. and Foreign
 * Patents, patents in process, and are protected by trade secret or copyright
 * law. Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained from
 * Adobe Systems Incorporated.
 */

package com.adobe.xfa.ut;

import java.awt.Point;
import java.util.ArrayList;
import java.util.List;

/**
 * The PictureFmt class defines methods to parse and format data
 * according to XFA picture patterns.
 * 
 * Here's a snippet of code illustrating its use to format a date string:
 * 
 * 

 *     import com.adobe.xfa.ut.PictureFmt;
 *     ...
 *     StringBufer sResult = new StringBuilder();
 *     PictureFmt oFmt = new PictureFmt("en"); 
 *     if (oFmt.parse("28/2/2000", "D/M/YYYY", sResult)) 
 *         oFmt.format(sResult.toString(), "EEEE', the 'D' of 'MMMM', 'YYYY", sResult) 
 *     ...
 * 
*

* PictureFmt also defines methods to validate picture patterns. * Specifically, the methods *

    *
  • * {@link PictureFmt#isDatePictureValid(String)}, *
  • * {@link PictureFmt#isTimePictureValid(String)}, *
  • * {@link PictureFmt#isNumericPictureValid(String)}, *
  • * {@link PictureFmt#isTextPictureValid(String)}, *
* {@link PictureFmt#isZeroPictureValid(String)}, and, *
  • * {@link PictureFmt#isNullPictureValid(String)}. * * are used for validating the syntax of the given source for each of the * six categories of pictures. This includes validating the well-formedness of * patterns like * category{subpicture} and * category(locale){subpicture}, * validating the well-formedness of literals, and ensuring the given source * symbols all belong to one category of picture. As an example, * the time picture pattern: *
    
     *     h:MM:SS 'o'clock 'A X
     * 
    * is syntactically invalid - a quote is missing and X is not a valid time * picture symbol. *

    * PictureFmt also defines methods to semantically validate picture * patterns. The methods *

      *
    • {@link PictureFmt#isDatePicture(String)}, *
    • {@link PictureFmt#isTimePicture(String)}, *
    • {@link PictureFmt#isNumericPicture(String)}, and, *
    • {@link PictureFmt#isTextPicture(String)} *
    * are used for semantially validating the given picture. This means that the * combination of XFA symbols constitutes a valid XFA picture pattern. A time * picture pattern like: *
    
     *     h:MM:SS 'o''clock 'Z
     * 
    * is semantically invalid when used to parse time input -- requesting a time * from a 12-hour clock without the meridiem could never yield a correct time * value. A date picture pattern like: EEEE, MMMM YYYY is semantically invalid * when used to parse date input -- requesting a date without the day of the * month could never yield a correct date value. *

    * Do note however, that semantically invalid pictures patterns are used in * output formatting in acceptable circumstances. So apply these method with * discretion. * * @exclude from published api. */ public final class PictureFmt { /* * This function emulates ResolveRange method in C++ side of XTG. That method takes a String and rationalizes the start and * end indices as follows: * If startIndex>s.length(), make startIndex=s.length() * If endIndex>s.length(), make endIndex=s.length() * Since, unlike C++, these values can't be returned, envelope them as a Point * with Point.x = startIndex (maybe modified) * and Point.y = endIndex (maybe modified) */ /** @exclude from published api. */ public static Point resolveRange(String s, int startIndex, int endIndex){ if (startIndex>s.length()) startIndex=s.length(); if (endIndex>s.length()) endIndex=s.length(); return new Point(startIndex, endIndex); } /** * Instantiates an PictureFmt object. * @param sLocale * the locale name. */ public PictureFmt(String sLocale /* = LcLocale.getLocale() */) { msLocale = sLocale; } /** * Formats a given data source according to the given picture. * * @param sSource * the source data in canonical format. * @param sPicture * the formatting picture. * @param sResult * the resulting string, which may be empty upon error. * @return * boolean true if successful and false otherwise. */ @FindBugsSuppress(pattern="NP_LOAD_OF_KNOWN_NULL_VALUE") // false positive public boolean format(String sSource, String sPicture, StringBuilder sResult) { sResult.setLength(0); // // If no formatting picture found Then return source. // if (StringUtils.isEmpty(sPicture)) { sResult.append(sSource); return true; } // // Segregate alternate pictures into a list. // List oAlt = new ArrayList(); if (! getAlternates(sPicture, oAlt)) { return true; } // // For each alternate picture Do ... // boolean bSuccess = false; for (int i = 0; i < oAlt.size(); i++) { String sMask = interpret(oAlt.get(i)); StringBuilder sDateMask = new StringBuilder(); StringBuilder sTimeMask = new StringBuilder(); // // Try formatting each alternate (in picture category order, except // for null data, which can ONLY be formatted with a null picture). // if (sSource == null) { if (isNullPicture(sMask)) bSuccess = formatNull(sSource, sMask, msLocale, sResult); } // Watson bug 1660883, allows text{} to return an empty string and success. else if (sSource.length() == 0) { if (isEmptyPicture(sMask)) { bSuccess = true; sResult.setLength(0); } // don't need to check the null picture because the input // to formatNull must be a null string, instead assume failure. } else if (isNumericPicture(sMask)) bSuccess = formatNumeric(sSource, sMask, msLocale, sResult); else if (isNullPicture(sMask)) bSuccess = formatNull(sSource, sMask, msLocale, sResult); else if (isZeroPicture(sMask)) bSuccess = formatZero(sSource, sMask, msLocale, sResult); else if (isDateTimePicture(sMask, sDateMask, sTimeMask)) bSuccess = formatDateTime(sSource, sMask, sDateMask.toString(), sTimeMask.toString(), msLocale, sResult, true); else if (isDatePicture(sMask)) bSuccess = formatDate(sSource, sMask, msLocale, sResult, true); else if (isTimePicture(sMask)) bSuccess = formatTime(sSource, sMask, msLocale, sResult, true); else if (isTextPicture(sMask)) bSuccess = formatText(sSource, sMask, msLocale, sResult); else if (isCompoundPicture(sMask)) bSuccess = formatCompound(sSource, sMask, msLocale, sResult); else bSuccess = false; // // Were done one first successful format. // if (bSuccess) break; } return bSuccess; } /** * Parses a given data source according to the given picture. * * @param sSource * the source data. * @param sPicture * the parsing picture. * @param pbSuccess * the canonical result. * @return * the string result. */ public String parse(String sSource, String sPicture, BooleanHolder pbSuccess) { // // If no formatting picture found Then return source. // if (StringUtils.isEmpty(sPicture)) { return sSource; } // // If source is null string Then return false. // if (sSource == null) { if (pbSuccess != null) pbSuccess.value = true; return null; } // // Segregate alternate pictures into a list. // List oAlt = new ArrayList(); if (! getAlternates(sPicture, oAlt)) return ""; // // For each alternate picture Do ... // boolean bSuccess = false; StringHolder sResult = new StringHolder(); StringBuilder sDateMask = new StringBuilder(); StringBuilder sTimeMask = new StringBuilder(); for (int i = 0; i < oAlt.size(); i++) { String sMask = interpret(oAlt.get(i)); sDateMask.setLength(0); sTimeMask.setLength(0); // JavaPort: The following line of C++ implementation has the // unintended side-effect of changing whether the result is null // or empty, depending on the length of the input. // This code emulates that behaviour, but it is probably a bug. //sResult.ReAlloc(sSource.Length(), FALSE, sSource.GetThreadId()); sResult.value = sSource.length() > 0 ? "" : null; // // Try parsing each alternate in picture category order. // if (isNumericPicture(sMask)) bSuccess = parseNumeric(sSource, sMask, msLocale, sResult); else if (isNullPicture(sMask)) bSuccess = parseNull(sSource, sMask, msLocale, sResult); else if (isZeroPicture(sMask)) bSuccess = parseZero(sSource, sMask, msLocale, sResult); else if (isDateTimePicture(sMask, sDateMask, sTimeMask)) bSuccess = parseDateTime(sSource, sMask, sDateMask.toString(), sTimeMask.toString(), msLocale, sResult, true); else if (isDatePicture(sMask)) bSuccess = parseDate(sSource, sMask, msLocale, sResult, true); else if (isTimePicture(sMask)) bSuccess = parseTime(sSource, sMask, msLocale, sResult, true); else if (isTextPicture(sMask)) bSuccess = parseText(sSource, sMask, msLocale, sResult); else if (isCompoundPicture(sMask)) bSuccess = parseCompound(sSource, sMask, msLocale, sResult); else bSuccess = false; // // Were done one first successful parse. // if (bSuccess) break; } if (pbSuccess != null) pbSuccess.value = bSuccess; return sResult.value; } /** * Converts a F99 picture to an equivalent XFA picture. * F99 pictures contain either double quote enclosed literals, * or single quote enclosed literals. Change all to single * quote enclosed literals, suitably escaping any embedded * double quotes. * * @param sPicture * the source picture. * @return * the equivalent XFA picture. */ public static String FF99ToXFA(String sPicture) { int picLen = sPicture.length(); int needs_escapes = 0; for (int i = 0; i < picLen; i++) { char chr = sPicture.charAt(i); if (chr == '\"' || chr == '\'') needs_escapes++; } StringBuilder sRes = new StringBuilder(sPicture.length() + needs_escapes); final int START = 0; final int SGLQUOTE = 1; final int DBLQUOTE = 2; // // A finite state machine to translate // '..."...' to '..."...' and // "...'..." to '...''...'. // int eState = START; for (int i = 0; i < picLen; ) { char chr = sPicture.charAt(i++); if (eState == START) { if (chr == '\'') { eState = SGLQUOTE; } else if (chr == '\"') { eState = DBLQUOTE; chr = '\''; } } else if (eState == SGLQUOTE) { if (chr == '\'') { eState = START; } else if (chr == '\"') { sRes.append(chr); } } else if (eState == DBLQUOTE) { if (chr == '\"') { eState = START; chr = '\''; } else if (chr == '\'') { sRes.append(chr); } } sRes.append(chr); } return sRes.toString(); } /** * Formats a given data source according to the given compound picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the compound picture. * @param sLocale * the locale name. * @param sResult * the resulting string, which may be empty upon error. * @return * This method is not operational! */ public static boolean formatCompound(String sSource, String sPicture, String sLocale, StringBuilder sResult) { MsgFormatPos oMessage = new MsgFormatPos(ResId.UNSUPPORTED_OPERATION, "PictureFmt#formatCompound"); oMessage.format("formatCompound"); throw new ExFull(oMessage); } /** * Formats a given data source according to the given date picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the date picture. * @param sLocale * the locale name. * @param sResult * the resulting string, which may be empty upon error. * @param bAsLocal * interpret the source data as a local date when true, * and a GMT date when false. * @return * boolean true upon success and false otherwise. */ public static boolean formatDate(String sSource, String sPicture, String sLocale, StringBuilder sResult, boolean bAsLocal) { assert(sResult != null); sResult.setLength(0); if (sSource == null) return false; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sDateMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sDateMask) && ! sCategory.toString().equals(gsDate)) { sDateMask.replace(0, sDateMask.length(), sPicture); } ISODate oDate = new ISODate(sSource, sLoc.toString()); if (oDate.isValid()) { if (bAsLocal) oDate.setLocalDate(); sResult.append(oDate.format(sDateMask.toString())); } return sResult.length() != 0; } /** * Formats a given data source according to the given datetime picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the datetime picture. * @param sDateMask * the date sub-picture. * @param sTimeMask * the time sub-picture. * @param sLocale * the locale name. * @param sResult * the resulting string, which may be empty upon error. * @param bAsLocal * interpret the data source as locale datetime when true, * and GMT datetime when false. * @return * boolean true upon success and false otherwise. */ public static boolean formatDateTime(String sSource, String sPicture, String sDateMask, String sTimeMask, String sLocale, StringBuilder sResult, boolean bAsLocal) { assert(sResult != null); sResult.setLength(0); if (sSource == null) return false; boolean bValid = true; String sFormattedDate = ""; String sFormattedTime = ""; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sDateSubMask = new StringBuilder(); StringBuilder sTimeSubMask = new StringBuilder(); if (! isSubPicture(sDateMask, 0, sCategory, sLoc, sDateSubMask) && ! sCategory.toString().startsWith(gsDate)) { sDateSubMask.replace(0, sDateSubMask.length(), sDateMask); } String sDateLocale = sLoc.toString(); sLoc.replace(0, sLoc.length(), sLocale); if (! isSubPicture(sTimeMask, 0, sCategory, sLoc, sTimeSubMask) && ! sCategory.toString().startsWith(gsTime)) { sTimeSubMask.replace(0, sTimeSubMask.length(), sTimeMask); } String sTimeLocale = sLoc.toString(); int nFound = sSource.indexOf('T'); if (nFound >= 0) { // // Extract the date and time data. // String sSourceDate = sSource.substring(0, nFound); String sSourceTime = sSource.substring(nFound + 1); // // Vantive 571490. Pass locale into ISODateTime constructor // ISODate oISODate = new ISODate(sSourceDate, sDateLocale); ISOTime oISOTime = new ISOTime(sSourceTime, sTimeLocale); bValid = oISODate.isValid() && oISOTime.isValid(); if (bValid) { if (bAsLocal) { oISODate.setLocalDate(); oISOTime.setLocalTime(); } sFormattedDate = oISODate.format(sDateSubMask.toString()); sFormattedTime = oISOTime.format(sTimeSubMask.toString()); } } else if ((nFound = sSource.indexOf(' ')) >= 0) { // // Extract the date and time data. // String sSourceDate = sSource.substring(0, nFound); String sSourceTime = sSource.substring(nFound + 1); // // Ensure source is in source locale's short date time format. // String sSourceDateFmt = new LcData(sLocale).getDateFormat(1); String sSourceTimeFmt = new LcData(sLocale).getTimeFormat(1); LcDate oDate = new LcDate(sSourceDate, sSourceDateFmt, sDateLocale, LcDate.DEFAULT_CENTURY_SPLIT); LcTime oTime = new LcTime(sSourceTime, sSourceTimeFmt, sTimeLocale); bValid = oDate.isValid() && oTime.isValid(); if (bValid) { if (bAsLocal) { oDate.setLocalDate(); oTime.setLocalTime(); } sFormattedDate = oDate.format(sDateSubMask.toString()); sFormattedTime = oTime.format(sTimeSubMask.toString()); } } else bValid = false; if (bValid) { if (sPicture.startsWith(gsDateTime)) { sResult.append(sDateMask); sResult.append(' '); sResult.append(sTimeMask); } else { sResult.replace(0, sResult.length(), sPicture); } // // Check for possible literal strings in the mask // int nEnd; int nCharPos = 0; while (nCharPos < sResult.length()) { int nPrevPos = nCharPos; char cChar = sResult.charAt(nCharPos++); if (cChar == '\'') { StringBuilder sLiteral = new StringBuilder(); nEnd = nCharPos; int n = getLiteralSubstr(sResult.toString(), cChar, nEnd, sLiteral); if (n > nEnd) { nEnd = n; sResult.replace(nPrevPos, nEnd, sLiteral.toString()); // // Watson #1278748. Subtract 2 since 2 quote chars // were removed. // nCharPos = nEnd - 2; } } } // // Vantive 571490. Search for 'date' rather than 'date{' // as we might have a locale in the format // int nDateTag = sResult.indexOf(gsDate); nEnd = sResult.substring(nDateTag, sResult.length()).indexOf('}'); sResult.replace(nDateTag, nDateTag + nEnd + 1, sFormattedDate); int nTimeTag = sResult.indexOf(gsTime); nEnd = sResult.substring(nTimeTag, sResult.length()).indexOf('}'); sResult.replace(nTimeTag, nTimeTag + nEnd + 1, sFormattedTime); } return bValid; } /** * Formats a given data source according to the given null picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the null picture. * @param sLocale * the locale name. * @param sResult * the resulting string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean formatNull(String sSource, String sPicture, String sLocale, StringBuilder sResult) { assert(sResult != null); sResult.setLength(0); if (sSource != null) return false; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sNullMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sNullMask) && ! sCategory.toString().equals(gsNull)) { sNullMask.replace(0, sNullMask.length(), sPicture); } if (sNullMask.length() == 0) return true; LcNum oNum = new LcNum("0", sLoc.toString()); if (oNum.isValid()) sResult.append(oNum.format(sNullMask.toString(), null)); return sResult.length() != 0; } /** * Formats a given data source according to the given numeric picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the numeric picture. * @param sLocale * the locale name. * @param sResult * the resulting string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean formatNumeric(String sSource, String sPicture, String sLocale, StringBuilder sResult) { assert(sResult != null); sResult.setLength(0); if (sSource == null) return false; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sNumMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sNumMask) && ! sCategory.toString().equals(gsNum)) { sNumMask.replace(0, sNumMask.length(), sPicture); } LcNum oNum = new LcNum(sSource, sLoc.toString()); if (oNum.isValid()) sResult.append(oNum.format(sNumMask.toString(), null)); return sResult.length() != 0; } /** * Formats a given data source according to the given text picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the text picture. * @param sLocale * the locale name. * @param sResult * the resulting string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean formatText(String sSource, String sPicture, String sLocale, StringBuilder sResult) { assert(sResult != null); sResult.setLength(0); StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sTextMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sTextMask) && ! sCategory.toString().equals(gsText)) { sTextMask.replace(0, sTextMask.length(), sPicture); } LcText oText = new LcText(sSource, sLoc.toString()); if (oText.isValid()) sResult.append(oText.format(sTextMask.toString())); return sResult.length() != 0; } /** * Formats a given data source according to the given time picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the time picture. * @param sLocale * the locale name. * @param sResult * the resulting string, which may be empty upon error. * @param bAsLocal * interpret the data source as local time when true, * and a GMT time when false. * @return * boolean true upon success and false otherwise. */ public static boolean formatTime(String sSource, String sPicture, String sLocale, StringBuilder sResult, boolean bAsLocal) { assert(sResult != null); sResult.setLength(0); if (sSource == null) return false; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sTimeMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sTimeMask) && ! sCategory.toString().equals(gsTime)) { sTimeMask.replace(0, sTimeMask.length(), sPicture); } ISOTime oTime = new ISOTime(sSource, sLoc.toString()); if (oTime.isValid()) { if (bAsLocal) oTime.setLocalTime(); sResult.append(oTime.format(sTimeMask.toString())); } return sResult.length() != 0; } /** * Formats a given data source according to the given zero picture * under the given locale. * * @param sSource * the source data. It must be empty or zero! * @param sPicture * the zero picture. * @param sLocale * the locale name. * @param sResult * the resulting string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean formatZero(String sSource, String sPicture, String sLocale, StringBuilder sResult) { assert(sResult != null); sResult.setLength(0); if (sSource == null) return false; if (! sSource.equals("0")) return false; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sZeroMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sZeroMask) && ! sCategory.toString().equals(gsZero)) { sZeroMask.replace(0, sZeroMask.length(), sPicture); } if (sZeroMask.length() == 0) return true; LcNum oNum = new LcNum(sSource, sLoc.toString()); if (oNum.isValid()) sResult.append(oNum.format(sZeroMask.toString(), null)); return sResult.length() != 0; } /** * Gets all the picture alternatives. * * @param sSource * the source picture. Alternate pictures are each * separated by the vertical bar '|' character. * @param oAlternates * the object to be populated with all the alternate * pictures found in the source. * @return * boolean true upon success and false if the source picture is * invalid. */ @FindBugsSuppress(code="DB") public static boolean getAlternates(String sSource, List oAlternates) { char prevChr = 0; int chrCnt = 0; boolean inQuoted = false; boolean inQuoteQuoted = false; // // Foreach each character of the picture Do ... // int picLen = sSource.length(); int i = 0; int k = i; while (i < picLen) { int j = i; char chr = sSource.charAt(i++); // // If seen a quote within a quoted string ... // if (inQuoteQuoted) { if (chr == '\'') { // cases like '...'' chrCnt = 0; } else { // cases like '...'X inQuoted = false; chrCnt = 1; prevChr = chr; } inQuoteQuoted = false; } // // Elif within a quoted string ... // else if (inQuoted) { if (chr == '\'') { // cases like '...' inQuoteQuoted = true; } chrCnt++; prevChr = chr; } // // Elif start of a quoted string ... // else if (chr == '\'') { if (chrCnt > 0) { // cases like ...X' if (prevChr == '|') { oAlternates.add(sSource.substring(k, j - 1)); k = j; } chrCnt = 0; prevChr = 0; } inQuoted = true; } // // Elif start of a metacharacter ... // else if (DateTimeUtil.matchChr(LcNum.NUMERIC_PICTURE_SYMBOLS, chr) || DateTimeUtil.matchChr(LcText.TEXT_PICTURE_SYMBOLS, chr) || DateTimeUtil.matchChr(LcDate.DATE_PICTURE_SYMBOLS, chr) || DateTimeUtil.matchChr(LcTime.TIME_PICTURE_SYMBOLS, chr) || ('a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z')) { if (chr != prevChr) { if (chrCnt > 0) { if (prevChr == '|') { oAlternates.add(sSource.substring(k, j - 1)); k = j; } chrCnt = 0; } prevChr = chr; } chrCnt++; } // // Elif start of a literal ... // else if (chrCnt > 0) { // cases like AA- if (prevChr == '|') { oAlternates.add(sSource.substring(k, j - 1)); k = j; } chrCnt = 1; prevChr = chr; } // // Else yet another literal ... // else { if (prevChr == '|') { oAlternates.add(sSource.substring(k, j - 1)); k = j; } chrCnt = 1; prevChr = chr; } } // // Ensure quoted string is terminated. // if (inQuoteQuoted) inQuoted = false; if (inQuoted) { int n = oAlternates.size(); while (n-- > 0) oAlternates.remove(n); return false; } // // Handle any remaining items in the picture. // if (prevChr > 0 && chrCnt > 0) { assert(i == picLen); oAlternates.add(sSource.substring(k, i)); } return true; } /** * Gets the locale given a valid picture and category. * * @param sPicture * the valid picture. * @param sCategory * the picture category: one of "date", "time", "num", "text", * "null" or "zero". * @param sLocale * the returned locale. * @return * boolean true if the source picture is semantically valid, * and false otherwise. */ public static boolean getLocaleFromPicture(String sPicture, String sCategory, StringBuilder sLocale) { int nPictIndex = 0; int nPrevIndex = 0; int nCategoryBeg, nCategoryEnd; int nLocaleBeg, nLocaleEnd; sLocale.setLength(0); while (nPictIndex < sPicture.length()) { nPrevIndex = nPictIndex; char cChar = sPicture.charAt(nPictIndex++); if (cChar == '\'') { int nIndex = getLiteralSubstr(sPicture, cChar, nPictIndex, null); if (nIndex == nPictIndex) { return false; } nPictIndex = nIndex; continue; } else if (isCharAlphabetic(cChar)) { nCategoryBeg = nPrevIndex; if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; while (isCharAlphabetic(sPicture.charAt(nPictIndex++))) { nPrevIndex = nPictIndex; if (nPictIndex == sPicture.length()) return false; } nCategoryEnd = nPrevIndex; nLocaleBeg = nLocaleEnd = nPictIndex; nPictIndex = nPrevIndex; cChar = sPicture.charAt(nPictIndex++); if (cChar == '(') { nLocaleBeg = nPictIndex; if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; while (sPicture.charAt(nPictIndex++) != ')') { nPrevIndex = nPictIndex; if (nPictIndex == sPicture.length()) return false; } nLocaleEnd = nPrevIndex; cChar = sPicture.charAt(nPictIndex++); } if (cChar == '{') { while (true) { if (nPictIndex == sPicture.length()) return false; cChar = sPicture.charAt(nPictIndex++); if (cChar == '\'') { int nIndex = getLiteralSubstr(sPicture, cChar, nPictIndex, null); if (nIndex == nPictIndex) return false; nPictIndex = nIndex; } else if (cChar == '}') { break; } } String sCandidate = sPicture.substring(nCategoryBeg, nCategoryEnd); if (sCandidate.equals(sCategory)) { if (sLocale.length() != 0) return false; sLocale.replace(0, sLocale.length(), sPicture.substring(nLocaleBeg, nLocaleEnd)); continue; } } return false; } else if (isCharNumeric(cChar)) { continue; } else if (isCharLiteral(cChar)) { continue; } else { return false; } } return true; } /** * Determines if the given picture has a sub-picture. If so, the * sub-picture's components are returned. Subpictures are of the form: * category{subpicture} or * category(locale){subpicture}. * * @param sPicture * the picture. * @param nPictIndex * the starting picture index. * @param sCategory * the picture's category. * @param sLocale * the picture's locale. * @param sSubMask * the picture's sub-picture. * @return * boolean true if there's a sub-picture, and false otherwise. */ public static boolean hasSubPicture(String sPicture, int nPictIndex, StringBuilder sCategory, StringBuilder sLocale, StringBuilder sSubMask) { int nLiteralBeg, nLiteralEnd; int nCategoryBeg, nCategoryEnd; int nLocaleBeg, nLocaleEnd; int nSubMaskBeg, nSubMaskEnd; String sSubCategory = ""; while (nPictIndex < sPicture.length()) { int nPrevIndex = nPictIndex; char cChar = sPicture.charAt(nPictIndex++); if (cChar == '\'') { nLiteralBeg = nPrevIndex; int nIndex = getLiteralSubstr(sPicture, cChar, nPictIndex, null); if (nIndex == nPictIndex) return false; nPictIndex = nIndex; nLiteralEnd = nPictIndex - 1; sSubMask.append(sPicture, nLiteralBeg, nLiteralEnd + 1); continue; } else if (isCharAlphabetic(cChar)) { nCategoryBeg = nPrevIndex; if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; while (isCharAlphabetic(sPicture.charAt(nPictIndex++))) { nPrevIndex = nPictIndex; if (nPictIndex == sPicture.length()) return false; } nCategoryEnd = nPrevIndex; nLocaleBeg = nLocaleEnd = nPictIndex; nPictIndex = nPrevIndex; cChar = sPicture.charAt(nPictIndex++); if (cChar == '.') { int nSubCategoryBeg = nPictIndex; if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; while (true) { cChar = sPicture.charAt(nPictIndex++); if (cChar == '(' || cChar == '{') break; nPrevIndex = nPictIndex; if (nPictIndex == sPicture.length()) return false; } int nSubCategoryEnd = nPrevIndex; sSubCategory = sPicture.substring(nSubCategoryBeg, nSubCategoryEnd); } if (cChar == '(') { nLocaleBeg = nPictIndex; if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; while (sPicture.charAt(nPictIndex++) != ')') { nPrevIndex = nPictIndex; if (nPictIndex == sPicture.length()) return false; } nLocaleEnd = nPrevIndex; if (nLocaleEnd > nLocaleBeg) sLocale.replace(0, sLocale.length(), sPicture.substring(nLocaleBeg, nLocaleEnd)); cChar = sPicture.charAt(nPictIndex++); } if (cChar == '{') { nSubMaskBeg = nPictIndex; while (true) { if (nPictIndex >= sPicture.length()) return false; nPrevIndex = nPictIndex; cChar = sPicture.charAt(nPictIndex++); if (cChar == '\'') { int nIndex = getLiteralSubstr(sPicture, cChar, nPictIndex, null); if (nIndex == nPictIndex) return false; nPictIndex = nIndex; } else if (cChar == '}') { nSubMaskEnd = nPrevIndex; break; } } String sCandidate = sPicture.substring(nCategoryBeg, nCategoryEnd); if (sCandidate.equals(gsNull) || sCandidate.equals(gsZero) || sCandidate.equals(gsText)) { sCategory.append(sCandidate); if (sLocale.length() == 0) sLocale.append(LcLocale.DEFAULT_LOCALE); sSubMask.append(sPicture, nSubMaskBeg, nSubMaskEnd); continue; } else if (sCandidate.equals(gsDate) || sCandidate.equals(gsTime)) { sCategory.append(sCandidate); if (sLocale.length() == 0) sLocale.append(LcLocale.DEFAULT_LOCALE); String sFmt = null; if (sSubCategory.length() == 0) { sFmt = sPicture.substring(nSubMaskBeg, nSubMaskEnd); } else if (sSubCategory.equals(gsShort)) { LcData oData = new LcData(sLocale.toString()); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.SHORT_FMT); else sFmt = oData.getTimeFormat(LcData.SHORT_FMT); } else if (sSubCategory.equals(gsMedium)) { LcData oData = new LcData(sLocale.toString()); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.MED_FMT); else sFmt = oData.getTimeFormat(LcData.MED_FMT); } else if (sSubCategory.equals(gsLong)) { LcData oData = new LcData(sLocale.toString()); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.LONG_FMT); else sFmt = oData.getTimeFormat(LcData.LONG_FMT); } else if (sSubCategory.equals(gsFull)) { LcData oData = new LcData(sLocale.toString()); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.FULL_FMT); else sFmt = oData.getTimeFormat(LcData.FULL_FMT); } else if (sSubCategory.equals(gsDefault)) { LcData oData = new LcData(sLocale.toString()); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.DEFLT_FMT); else sFmt = oData.getTimeFormat(LcData.DEFLT_FMT); } else { return false; } sSubMask.append(sFmt); continue; } else if (sCandidate.equals(gsNum)) { sCategory.append(sCandidate); if (sLocale.length() == 0) sLocale.append(LcLocale.DEFAULT_LOCALE); LcData oData = new LcData(sLocale.toString()); String sFmt = null; if (sSubCategory.length() == 0) { sFmt = sPicture.substring(nSubMaskBeg, nSubMaskEnd); } else if (sSubCategory.equals(gsInteger)) { int nOptn = LcData.WITH_GROUPINGS; sFmt = oData.getNumberFormat(LcData.INTEGRAL_FMT, nOptn); } else if (sSubCategory.equals(gsDecimal)) { int nOptn = LcData.withPrecision(~0) | LcData.WITH_GROUPINGS | LcData.KEEP_NINES; sFmt = oData.getNumberFormat(LcData.DECIMAL_FMT, nOptn); } else if (sSubCategory.equals(gsCurrency)) { int nOptn = LcData.withPrecision(~0) | LcData.WITH_GROUPINGS | LcData.KEEP_NINES; sFmt = oData.getNumberFormat(LcData.CURRENCY_FMT, nOptn); } else if (sSubCategory.equals(gsPercent)) { int nOptn = LcData.WITH_GROUPINGS; sFmt = oData.getNumberFormat(LcData.PERCENT_FMT, nOptn); } else { return false; } sSubMask.append(sFmt); continue; } else if (sCandidate.equals(gsDateTime)) { sCategory.append(sCandidate); if (sLocale.length() == 0) sLocale.append(LcLocale.DEFAULT_LOCALE); LcData oData = new LcData(sLocale.toString()); int nOptn = LcData.WITH_CATEGORIES; String sFmt = null; if (sSubCategory.equals(gsShort)) { sFmt = oData.getDateTimeFormat(LcData.SHORT_FMT, nOptn); } else if (sSubCategory.equals(gsMedium)) { sFmt = oData.getDateTimeFormat(LcData.MED_FMT, nOptn); } else if (sSubCategory.equals(gsLong)) { sFmt = oData.getDateTimeFormat(LcData.LONG_FMT, nOptn); } else if (sSubCategory.equals(gsFull)) { sFmt = oData.getDateTimeFormat(LcData.FULL_FMT, nOptn); } else if (sSubCategory.equals(gsDefault)) { sFmt = oData.getDateTimeFormat(LcData.DEFLT_FMT, nOptn); } else { return false; } sSubMask.append(sFmt); continue; } } return false; } else if (isCharNumeric(cChar)) { sSubMask.append(cChar); continue; } else if (isCharLiteral(cChar)) { sSubMask.append(cChar); continue; } else { return false; } } return true; } /* * Interprets any Unicode escape sequences (c;uXXXX) in a given string. * @param * the source string. * @return * the interpreted string. */ private static String interpret(String sSrc) { int sSrcLen = sSrc.length(); StringBuilder sDst = new StringBuilder(); for (int i = 0; i < sSrcLen; ) { char ch = sSrc.charAt(i++); if (ch == '\\' && sSrc.charAt(i + 1) == 'u' && i + 5 < sSrcLen && isCharHexDigit(sSrc.charAt(i + 2)) && isCharHexDigit(sSrc.charAt(i + 3)) && isCharHexDigit(sSrc.charAt(i + 4)) && isCharHexDigit(sSrc.charAt(i + 5))) { String sHex = sSrc.substring(i + 2, i + 6); try { char hHex = (char) Integer.parseInt(sHex, 16); sDst.append(hHex); i += 5; } catch (NumberFormatException e) { assert(e != null); } } else { sDst.append(ch); } } return sDst.toString(); } private static boolean isCharAlphabetic(char cChar) { return Character.isLetter(cChar); } private static boolean isCharHexDigit(char cChar) { return Character.isDigit(cChar) || ('a' <= Character.toLowerCase(cChar) && Character.toLowerCase(cChar) <= 'f'); } private static boolean isCharLiteral(char cChar) { return DateTimeUtil.matchChr(gsPictureLiterals, cChar); } private static boolean isCharNumeric(char cChar) { return (cChar == '0' || cChar == '9'); } private static boolean isCompoundPicture(String sPicture) { boolean bValid = true; int nCharIndex = 0; StringBuilder sCategory = new StringBuilder(); StringBuilder sLoc = new StringBuilder(); StringBuilder sMask = new StringBuilder(); while (nCharIndex < sPicture.length()) { int nPrevIndex = nCharIndex; char cChar = sPicture.charAt(nCharIndex++); // If this is an open quote, then skip the substring. if (cChar == '\'') { // Skip by the literal string including trailing quote. int nIndex = getLiteralSubstr(sPicture, cChar, nCharIndex, null); if (nIndex > nCharIndex) { nCharIndex = nIndex; continue; } bValid = false; } else if (isSubPicture(sPicture, nPrevIndex, sCategory, sLoc, sMask)) { if (sCategory.toString().startsWith(gsDate)) bValid = isDatePicture(sMask.toString()); else if (sCategory.toString().startsWith(gsTime)) bValid = isTimePicture(sMask.toString()); else if (sCategory.toString().equals(gsText)) bValid = isTextPicture(sMask.toString()); else if (sCategory.toString().equals(gsNull)) bValid = isNullPicture(sMask.toString()); else if (sCategory.toString().equals(gsZero)) bValid = isZeroPicture(sMask.toString()); else if (sCategory.toString().equals(gsNum)) bValid = isNumericPicture(sMask.toString()); if (! bValid) break; nPrevIndex += sCategory.length(); if (sLoc.length() != 0) nPrevIndex += sLoc.length() + 2; nPrevIndex += sMask.length() + 2; nCharIndex = nPrevIndex; } else if (isCharNumeric(cChar)) { continue; } else if (isCharLiteral(cChar)) { continue; } else { bValid = false; break; } } return bValid; } /** * Determines if the given picture is a date picture. * * @param sPicture * the source picture. * @return * boolean true if the source picture is syntactically valid, * and false otherwise. */ public static boolean isDatePicture(String sPicture) { return isPicture(sPicture, gsDate, LcDate.DATE_PICTURE_SYMBOLS); } /** * Determines if the given date picture is (semantically) valid. * * @param sPicture * the date picture. * @return * boolean true if the source picture is semantically valid, * and false otherwise. */ public static boolean isDatePictureValid(String sPicture) { StringBuilder sLoc = new StringBuilder(LcLocale.DEFAULT_LOCALE); StringBuilder sCat = new StringBuilder(); StringBuilder sPict = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCat, sLoc, sPict) || ! sCat.toString().equals(gsDate)) { sPict.replace(0, sPict.length(), sPicture); } // // Pick any date -- current date will do. // LcDate today = new LcDate(1, sLoc.toString(), LcDate.DEFAULT_CENTURY_SPLIT); // // Try parsing today's date as formatted. // return today.parse(today.format(sPict.toString()),sPict.toString()); } /** * Determines if the given picture is a date time picture. * * @param sPicture * the source picture. * @param sDateMask * the returned date picture found in the given source picture. * @param sTimeMask * the returned time picture found in the given source picture. * @return * boolean true if the source picture is syntactically valid, * and false otherwise. */ public static boolean isDateTimePicture(String sPicture, StringBuilder sDateMask, StringBuilder sTimeMask) { assert(sDateMask != null); assert(sTimeMask != null); sDateMask.setLength(0); sTimeMask.setLength(0); for (int i = 0; i < sPicture.length(); ) { StringBuilder sCategory = new StringBuilder(); StringBuilder sLoc = new StringBuilder(); StringBuilder sMask = new StringBuilder(); int j = i; char cChar = sPicture.charAt(i++); if (cChar == '\'') { int k = getLiteralSubstr(sPicture, cChar, i, null); if (k > i) { i = k; continue; } } else if (isCharLiteral(cChar) || cChar == 'T') { continue; } else if (isSubPicture(sPicture, j, sCategory, sLoc, sMask)) { if (sCategory.toString().startsWith(gsDate) && isDatePicture(sMask.toString())) { j += sCategory.length(); if (sLoc.length() != 0) j += sLoc.length() + 2; if (sCategory.indexOf(".") < 0) j += sMask.length(); j += 2; sDateMask.append(sCategory); if (sLoc.length() != 0) { sDateMask.append('('); sDateMask.append(sLoc); sDateMask.append(')'); } sDateMask.append('{'); if (sCategory.indexOf(".") < 0) sDateMask.append(sMask); sDateMask.append('}'); i = j; continue; } if (sCategory.toString().startsWith(gsTime) && isTimePicture(sMask.toString())) { j += sCategory.length(); if (sLoc.length() != 0) j += sLoc.length() + 2; if (sCategory.indexOf(".") < 0) j += sMask.length(); j += 2; sTimeMask.append(sCategory); if (sLoc.length() != 0) { sTimeMask.append('('); sTimeMask.append(sLoc); sTimeMask.append(')'); } sTimeMask.append('{'); if (sCategory.indexOf(".") < 0) sTimeMask.append(sMask); sTimeMask.append('}'); i = j; continue; } if (sCategory.toString().startsWith(gsDateTime)) { if (! isDateTimePicture(sMask.toString(), sDateMask, sTimeMask)) return false; j += sPicture.length(); i = j; continue; } } return false; } return (sDateMask.length() != 0 && sTimeMask.length() != 0); } /** * Determimes if the given datetime picture is (semantically) valid. * * @param sPicture * the datetime picture. * @return * boolean true if the source picture is semantically valid, * and false otherwise. */ public static boolean isDateTimePictureValid(String sPicture) { StringBuilder sDatePict = new StringBuilder(); StringBuilder sTimePict = new StringBuilder(); if (! isDateTimePicture(sPicture, sDatePict, sTimePict)) return false; StringBuilder sLoc = new StringBuilder(LcLocale.DEFAULT_LOCALE); StringBuilder sCat = new StringBuilder(); StringBuilder sPict = new StringBuilder(); if (hasSubPicture(sDatePict.toString(), 0, sCat, sLoc, sPict)) sDatePict.replace(0, sDatePict.length(), sPict.toString()); // // Pick any date and try parsing today's date as formatted. // LcDate today = new LcDate(1, sLoc.toString(), LcDate.DEFAULT_CENTURY_SPLIT); if (! today.parse(today.format(sDatePict.toString()), sDatePict.toString())) return false; // // Repeat the above on the time component. // sLoc = new StringBuilder(LcLocale.DEFAULT_LOCALE); sPict.setLength(0); sCat.setLength(0); if (hasSubPicture(sTimePict.toString(), 0, sCat, sLoc, sPict)) sTimePict.replace(0, sTimePict.length(), sPict.toString()); // // Pick any time and try parsing current time as formatted. // LcTime now = new LcTime(1, sLoc.toString()); if (! now.parse(now.format(sTimePict.toString()), sTimePict.toString())) return false; return true; } /** * Determines if the given picture is a null picture. * * @param sPicture * the source picture. * @return * boolean true if the source picture is syntactically valid, * and false otherwise. */ public static boolean isNullPicture(String sPicture) { StringBuilder sCat = new StringBuilder(); StringBuilder sLoc = new StringBuilder(); StringBuilder sMask = new StringBuilder(); return isSubPicture(sPicture, 0, sCat, sLoc, sMask) && sCat.toString().equals(gsNull); } /** * Determines if the given picture is an empty picture. * * @param sPicture * the source picture. * @return * boolean true if the source picture is syntactically valid, * and false otherwise. */ public static boolean isEmptyPicture(String sPicture) { // A null picture must be named; we never infer it's presence StringBuilder sCat = new StringBuilder(); StringBuilder sLoc = new StringBuilder(); StringBuilder sMask = new StringBuilder(); return (isSubPicture(sPicture, 0, sCat, sLoc, sMask) && (sMask.toString().length() == 0) && !sCat.toString().equals(gsNull) && !sCat.toString().equals(gsZero)); } /** * Determimes if the given null picture is (semantically) valid. * * @param sPicture * the null picture. * @return * boolean true if the source picture is semantically valid, * and false otherwise. */ public static boolean isNullPictureValid(String sPicture) { StringBuilder sLoc = new StringBuilder(LcLocale.DEFAULT_LOCALE); StringBuilder sCat = new StringBuilder(); StringBuilder sPict = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCat, sLoc, sPict) || ! sCat.toString().equals(gsNull)) { sPict.replace(0, sPict.length(), sPicture); } // // Pick a number -- one will do (zero will not). // LcNum one = new LcNum("1", sLoc.toString()); // // Try parsing number as formatted. // return one.parse(one.format(sPict.toString(), null), sPict.toString()); } /** * Determimes if the given picture is a numeric picture. * * @param sPicture * the source picture. * @return * boolean true if the source picture is syntactically valid, * and false otherwise. */ public static boolean isNumericPicture(String sPicture) { return isPicture(sPicture, gsNum, LcNum.NUMERIC_PICTURE_SYMBOLS); } /** * Determimes if the given numeric picture is (semantically) valid. * * @param sPicture * the numeric picture. * @return * boolean true if the source picture is semantically valid, * and false otherwise. */ public static boolean isNumericPictureValid(String sPicture) { StringBuilder sLoc = new StringBuilder(LcLocale.DEFAULT_LOCALE); StringBuilder sCat = new StringBuilder(); StringBuilder sPict = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCat, sLoc, sPict) || ! sCat.toString().equals(gsNum)) { sPict.replace(0, sPict.length(), sPicture); } // // Pick a number -- one will do (zero will not). // StringBuilder sOne = new StringBuilder("1"); // // Fix for Watson 115121. Determining a number that will parse // as formatted is getting increasing difficult what with // fractional 8, z and Z pictures. This is obviously a hack that // needs migration into the LcNum class -- Mike Tardif, Feb 16 2005. // int nDot = sPict.indexOf("."); if (nDot >= 0) { sOne.append('.'); if (sPict.indexOf("8", nDot + 1) >= 0) sOne.append('1'); else if (sPict.indexOf("z", nDot + 1) >= 0) sOne.append('1'); else if (sPict.indexOf("Z", nDot + 1) >= 0) sOne.append('1'); if (sPict.indexOf("%") >= 0) sOne.replace(0, sOne.length(), ".001"); } else if (sPict.indexOf("%") >= 0) sOne.replace(0, 1, ".00"); LcNum one = new LcNum(sOne.toString(), sLoc.toString()); // // Try parsing number as formatted. // LcNum num = new LcNum(one.format(sPict.toString(), null), sPict.toString()); return num.isValid(); } private static boolean isPicture(String sPicture, String sCategory, String sSymbols) { StringBuilder sCat = new StringBuilder(); StringBuilder sLoc = new StringBuilder(); StringBuilder sMask = new StringBuilder(); for (int i = 0; i < sPicture.length(); ) { int j = i; char cChar = sPicture.charAt(i++); if (cChar == '\'') { int k = getLiteralSubstr(sPicture, cChar, i, null); if (k > i) { i = k; continue; } } else if (DateTimeUtil.matchChr(gsPictureLiterals, cChar)) { continue; } else if (isSubPicture(sPicture, j, sCat, sLoc, sMask) && sCat.toString().startsWith(sCategory)) { String sCatStr = sCat.toString(); String sMaskStr = sMask.toString(); if ((sCatStr.startsWith(gsNum) && isNumericPicture(sMaskStr)) || (sCatStr.equals(gsNull) && isNullPicture(sMaskStr)) || (sCatStr.equals(gsZero) && isZeroPicture(sMaskStr)) || (sCatStr.equals(gsText) && isTextPicture(sMaskStr)) || (sCatStr.startsWith(gsDate) && isDatePicture(sMaskStr)) || (sCatStr.startsWith(gsTime) && isTimePicture(sMaskStr))) { j += sCat.length(); if (sLoc.length() != 0) j += sLoc.length() + 2; j += sMask.length() + 2; i = j; continue; } } else if (DateTimeUtil.matchChr(sSymbols, cChar)) { if (sSymbols == LcNum.NUMERIC_PICTURE_SYMBOLS) { // Further check for some numeric picture pattern symbol: // like "CR","cr","db", "DB" // They need to show up as one unit if (cChar =='C' || cChar =='c' || cChar =='d' || cChar =='D') { // Get next character if (i < sPicture.length()) { char cNextChar = sPicture.charAt(i++); if ((cChar =='C' && cNextChar != 'R') || (cChar =='c' && cNextChar != 'r') || (cChar =='d' && cNextChar != 'b') || (cChar =='D' && cNextChar != 'B') ) return false; } else return false; // to the end of the picture } else if (cChar=='r' || cChar=='R' || cChar=='b' || cChar=='B') return false; // They can't be lead symbol } continue; } return false; } return true; } /** * Determimes if the given picture has a sub-picture, * and if so, returns the picture's category, locale, and sub-picture. * * @param sPicture * the source picture. * @param nPictIndex * the starting character index within the given source picture. * @param sCategory * the picture's category. * @param sLocale * the picture's locale. * @param sSubMask * the picture's sub-picture. * @return * boolean true if the picture is a locale sensitive picture * and false otherwise. */ public static boolean isSubPicture(String sPicture, int nPictIndex, StringBuilder sCategory, StringBuilder sLocale, StringBuilder sSubMask) { int nCategoryBeg, nCategoryEnd; int nLocaleBeg, nLocaleEnd; int nSubMaskBeg, nSubMaskEnd; String sSubCategory = ""; sCategory.setLength(0); sSubMask.setLength(0); int nPrevIndex = nPictIndex; char cChar = sPicture.charAt(nPictIndex++); if (isCharAlphabetic(cChar)) { nCategoryBeg = nPrevIndex; if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; while (isCharAlphabetic(sPicture.charAt(nPictIndex++))) { nPrevIndex = nPictIndex; if (nPictIndex == sPicture.length()) return false; } nCategoryEnd = nPrevIndex; nLocaleBeg = nLocaleEnd = nPictIndex; nPictIndex = nPrevIndex; cChar = sPicture.charAt(nPictIndex++); if (cChar == '.') { int nSubCategoryBeg = nPictIndex; if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; while (true) { cChar = sPicture.charAt(nPictIndex++); if (cChar == '(' || cChar == '{') break; nPrevIndex = nPictIndex; if (nPictIndex == sPicture.length()) return false; } int nSubCategoryEnd = nPrevIndex; sSubCategory = sPicture.substring(nSubCategoryBeg, nSubCategoryEnd); } if (cChar == '(') { nLocaleBeg = nPictIndex; if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; while (sPicture.charAt(nPictIndex++) != ')') { nPrevIndex = nPictIndex; if (nPictIndex == sPicture.length()) return false; } nLocaleEnd = nPrevIndex; cChar = sPicture.charAt(nPictIndex++); } if (cChar == '{') { nSubMaskBeg = nPictIndex; while (true) { if (nPictIndex == sPicture.length()) return false; nPrevIndex = nPictIndex; cChar = sPicture.charAt(nPictIndex++); if (cChar == '\'') { int nIndex = getLiteralSubstr(sPicture, cChar, nPictIndex, null); if (nIndex == nPictIndex) return false; nPictIndex = nIndex; } else if (cChar == '}') { nSubMaskEnd = nPrevIndex; break; } } String sCandidate = sPicture.substring(nCategoryBeg, nCategoryEnd); if (sCandidate.equals(gsNull) || sCandidate.equals(gsZero) || sCandidate.equals(gsText)) { sCategory.replace(0, sCategory.length(), sCandidate); if (nLocaleEnd > nLocaleBeg) sLocale.replace(0, sLocale.length(), sPicture.substring(nLocaleBeg, nLocaleEnd)); sSubMask.replace(0, sSubMask.length(), sPicture.substring(nSubMaskBeg, nSubMaskEnd)); return true; } else if (sCandidate.equals(gsDate) || sCandidate.equals(gsTime)) { sCategory.replace(0, sCategory.length(), sCandidate); if (nLocaleEnd > nLocaleBeg) sLocale.replace(0, sLocale.length(), sPicture.substring(nLocaleBeg, nLocaleEnd)); String sLoc = LcLocale.DEFAULT_LOCALE; if (sLocale.length() != 0) sLoc = sLocale.toString(); String sFmt = null; if (sSubCategory.length() == 0) { sFmt = sPicture.substring(nSubMaskBeg, nSubMaskEnd); } else if (sSubCategory.equals(gsShort)) { LcData oData = new LcData(sLoc); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.SHORT_FMT); else sFmt = oData.getTimeFormat(LcData.SHORT_FMT); } else if (sSubCategory.equals(gsMedium)) { LcData oData = new LcData(sLoc); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.MED_FMT); else sFmt = oData.getTimeFormat(LcData.MED_FMT); } else if (sSubCategory.equals(gsLong)) { LcData oData = new LcData(sLoc); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.LONG_FMT); else sFmt = oData.getTimeFormat(LcData.LONG_FMT); } else if (sSubCategory.equals(gsFull)) { LcData oData = new LcData(sLoc); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.FULL_FMT); else sFmt = oData.getTimeFormat(LcData.FULL_FMT); } else if (sSubCategory.equals(gsDefault)) { LcData oData = new LcData(sLoc); if (sCandidate.equals(gsDate)) sFmt = oData.getDateFormat(LcData.DEFLT_FMT); else sFmt = oData.getTimeFormat(LcData.DEFLT_FMT); } else { return false; } sSubMask.replace(0, sSubMask.length(), sFmt); if (sSubCategory.length() != 0) { sCategory.append('.'); sCategory.append(sSubCategory); } return true; } else if (sCandidate.equals(gsNum)) { sCategory.replace(0, sCategory.length(), sCandidate); if (nLocaleEnd > nLocaleBeg) sLocale.replace(0, sLocale.length(), sPicture.substring(nLocaleBeg, nLocaleEnd)); String sLoc = LcLocale.DEFAULT_LOCALE; if (sLocale.length() != 0) sLoc = sLocale.toString(); String sFmt = null; if (sSubCategory.length() == 0) { sFmt = sPicture.substring(nSubMaskBeg, nSubMaskEnd); } else if (sSubCategory.equals(gsInteger)) { LcData oData = new LcData(sLoc); int nOptn = LcData.WITH_GROUPINGS; sFmt = oData.getNumberFormat(LcData.INTEGRAL_FMT, nOptn); } else if (sSubCategory.equals(gsDecimal)) { LcData oData = new LcData(sLoc); int nOptn = LcData.withPrecision(~0) | LcData.WITH_GROUPINGS; sFmt = oData.getNumberFormat(LcData.DECIMAL_FMT, nOptn); } else if (sSubCategory.equals(gsCurrency)) { LcData oData = new LcData(sLoc); int nOptn = LcData.withPrecision(~0) | LcData.WITH_GROUPINGS; sFmt = oData.getNumberFormat(LcData.CURRENCY_FMT, nOptn); } else if (sSubCategory.equals(gsPercent)) { LcData oData = new LcData(sLoc); int nOptn = LcData.WITH_GROUPINGS; sFmt = oData.getNumberFormat(LcData.PERCENT_FMT, nOptn); } else { return false; } sSubMask.replace(0, sSubMask.length(), sFmt); if (sSubCategory.length() != 0) { sCategory.append('.'); sCategory.append(sSubCategory); } return true; } else if (sCandidate.equals(gsDateTime)) { sCategory.replace(0, sCategory.length(), sCandidate); if (nLocaleEnd > nLocaleBeg) sLocale.replace(0, sLocale.length(), sPicture.substring(nLocaleBeg, nLocaleEnd)); String sLoc = LcLocale.DEFAULT_LOCALE; if (sLocale.length() != 0) sLoc = sLocale.toString(); String sFmt = null; LcData oData = new LcData(sLoc); int nOptn = LcData.WITH_CATEGORIES; if (sSubCategory.equals(gsShort)) { sFmt = oData.getDateTimeFormat(LcData.SHORT_FMT, nOptn); } else if (sSubCategory.equals(gsMedium)) { sFmt = oData.getDateTimeFormat(LcData.MED_FMT, nOptn); } else if (sSubCategory.equals(gsLong)) { sFmt = oData.getDateTimeFormat(LcData.LONG_FMT, nOptn); } else if (sSubCategory.equals(gsFull)) { sFmt = oData.getDateTimeFormat(LcData.FULL_FMT, nOptn); } else if (sSubCategory.equals(gsDefault)) { sFmt = oData.getDateTimeFormat(LcData.DEFLT_FMT, nOptn); } else { return false; } sSubMask.replace(0, sSubMask.length(), sFmt); if (sSubCategory.length() != 0) { sCategory.append('.'); sCategory.append(sSubCategory); } int nCurly = sSubMask.indexOf("date{"); if (nCurly >= 0) { nCurly += 4; sSubMask.insert(nCurly, ')'); sSubMask.insert(nCurly, sLoc); sSubMask.insert(nCurly, '('); } nCurly = sSubMask.indexOf("time{"); if (nCurly >= 0) { nCurly += 4; sSubMask.insert(nCurly, ')'); sSubMask.insert(nCurly, sLoc); sSubMask.insert(nCurly, '('); } return true; } } } return false; } /** * Determines if the given picture is a text picture. * * @param sPicture * the source picture. * @return * boolean true if the source picture is syntactically valid, * and false otherwise. */ public static boolean isTextPicture(String sPicture) { return isPicture(sPicture, gsText, LcText.TEXT_PICTURE_SYMBOLS); } /** * Determines if the given text picture is (semantically) valid. * * @param sPicture * the text picture. * @return * boolean true if the source picture is semantically valid, * and false otherwise. */ public static boolean isTextPictureValid(String sPicture) { StringBuilder sLoc = new StringBuilder(LcLocale.DEFAULT_LOCALE); StringBuilder sCat = new StringBuilder(); StringBuilder sPict = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCat, sLoc, sPict) || ! sCat.toString().equals(gsText)) { sPict.replace(0, sPict.length(), sPicture); } if (false) { // NOPMD // // Pick any text -- nothing will do. // LcText nothing = new LcText("", sLoc.toString()); // // Try parsing nothing as formatted. // LcText text = new LcText(nothing.format(sPict.toString()), sPict.toString(), sLoc.toString()); return text.isValid(); } else { return true; } } /** * Determines if the given picture is a time picture. * * @param sPicture * the source picture. * @return * boolean true if the source picture is syntactically valid, * and false otherwise. */ public static boolean isTimePicture(String sPicture) { return isPicture(sPicture, gsTime, LcTime.TIME_PICTURE_SYMBOLS); } /** * Determines if the given time picture is (semantically) valid. * * @param sPicture * the time picture. * @return * boolean true if the source picture is semantically valid, * and false otherwise. */ public static boolean isTimePictureValid(String sPicture) { StringBuilder sLoc = new StringBuilder(LcLocale.DEFAULT_LOCALE); StringBuilder sCat = new StringBuilder(); StringBuilder sPict = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCat, sLoc, sPict) || ! sCat.toString().equals(gsTime)) { sPict.replace(0, sPict.length(), sPicture); } // // Pick any time -- current time will do. // LcTime now = new LcTime(1, sLoc.toString()); // // Try parsing current time as formatted. // return now.parse(now.format(sPict.toString()), sPict.toString()); } /** * Determines if the given picture is a zero picture. * * @param sPicture * the source picture. * @return * boolean true if the source picture is syntactically valid, * and false otherwise. */ public static boolean isZeroPicture(String sPicture) { StringBuilder sCat = new StringBuilder(); StringBuilder sLoc = new StringBuilder(); StringBuilder sMask = new StringBuilder(); return (isSubPicture(sPicture, 0, sCat, sLoc, sMask) && sCat.toString().equals(gsZero)); } /** * Determines if the given zero picture is (semantically) valid. * * @param sPicture * the zero picture. * @return * boolean true if the source picture is semantically valid, * and false otherwise. */ public static boolean isZeroPictureValid(String sPicture) { StringBuilder sLoc = new StringBuilder(LcLocale.DEFAULT_LOCALE); StringBuilder sCat = new StringBuilder(); StringBuilder sPict = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCat, sLoc, sPict) || ! sCat.toString().equals(gsZero)) { sPict.replace(0, sPict.length(), sPicture); } // // Pick a number -- one will do (zero will not). // LcNum one = new LcNum("1", sLoc.toString()); // // Try parsing number as formatted. // return one.parse(one.format(sPict.toString(), null), sPict.toString()); } /** * Parses a given data source according to the given compound picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the compound picture. * @param sLocale * the locale name. * @param sResult * the resulting canonical string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean parseCompound(String sSource, String sPicture, String sLocale, StringHolder sResult) { MsgFormatPos oMessage = new MsgFormatPos(ResId.UNSUPPORTED_OPERATION, "PictureFmt#parseCompound"); oMessage.format("parseCompound"); throw new ExFull(oMessage); } /** * Parses a given data source according to the given date picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the date picture. * @param sLocale * the locale name. * @param sResult * the resulting canonical string, which may be empty upon error. * @param bAsLocal * return the canonical result as a local date when true, * and as a GMT date when false. * @return * boolean true upon success and false otherwise. */ public static boolean parseDate(String sSource, String sPicture, String sLocale, StringHolder sResult, boolean bAsLocal) { //sResult.value = ""; if (!StringUtils.isEmpty(sResult.value)) sResult.value = ""; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sDateMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sDateMask) && ! sCategory.toString().equals(gsDate)) { sDateMask.replace(0, sDateMask.length(), sPicture); } LcDate oDate = new LcDate(sSource, sDateMask.toString(), sLoc.toString(), LcDate.DEFAULT_CENTURY_SPLIT); if (oDate.isValid()) { ISODate oISODate = new ISODate(oDate.getDays()); if (bAsLocal) oISODate.setLocalDate(); sResult.value = oISODate.format(LcDate.DATE_FMT2); } return !StringUtils.isEmpty(sResult.value); } /** * Parses a given data source according to the given datetime picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the datetime picture. * @param sDateMask * the date sub-picture. * @param sTimeMask * the time sub-picture. * @param sLocale * the locale name. * @param sResult * the resulting canonical string, which may be empty upon error. * @param bAsLocal * return the canonical result as a local datetime when true, * and as a GMT datetime value when false. * @return * boolean true upon success and false otherwise. */ public static boolean parseDateTime(String sSource, String sPicture, String sDateMask, String sTimeMask, String sLocale, StringHolder sResult, boolean bAsLocal) { boolean bDateFirst = false; // // Determine date/time order. Why did we allow this in the first place? // int nDateFound = sPicture.indexOf(sDateMask); assert(nDateFound >= 0); int nTimeFound = sPicture.indexOf(sTimeMask); assert(nTimeFound >= 0); bDateFirst = (nDateFound < nTimeFound); // // Extract the prefix, infix and postfix mask literals from the picture. // String sPrefixMask, sInfixMask, sPostfixMask; if (bDateFirst) { { Point p=resolveRange(sPicture, 0, nDateFound); sPrefixMask = sPicture.substring(p.x,p.y); } { Point p=resolveRange(sPicture, nDateFound + sDateMask.length(), nTimeFound); sInfixMask = sPicture.substring(p.x,p.y); } { Point p=resolveRange(sPicture, nTimeFound + sTimeMask.length(), sPicture.length()); sPostfixMask = sPicture.substring(p.x,p.y); } } else { { Point p=resolveRange(sPicture, 0, nTimeFound); sPrefixMask = sPicture.substring(p.x,p.y); } { Point p=resolveRange(sPicture, nTimeFound + sTimeMask.length(), nDateFound); sInfixMask = sPicture.substring(p.x,p.y); } { Point p=resolveRange(sPicture, nDateFound + sDateMask.length(), sPicture.length()); sPostfixMask = sPicture.substring(p.x,p.y); } } // // Construct prefix, infix and postfix literals from mask literals. // LcDate oPrefixData = new LcDate(sLocale, LcDate.DEFAULT_CENTURY_SPLIT); String sPrefixMaskData = oPrefixData.format(sPrefixMask); LcDate oInfixData = new LcDate(sLocale, LcDate.DEFAULT_CENTURY_SPLIT); String sInfixMaskData = oInfixData.format(sInfixMask); LcDate oPostfixData = new LcDate(sLocale, LcDate.DEFAULT_CENTURY_SPLIT); String sPostfixMaskData = oPostfixData.format(sPostfixMask); // // Count number of occurences of infix literal. // int nInfixFound = 0; int nInfixSourceStart; if (sInfixMaskData.length() != 0) { int nAt, nStart = 0; while ((nAt = sSource.indexOf(sInfixMaskData, nStart)) >= 0) { nInfixSourceStart = nAt; nStart = nAt + sInfixMaskData.length(); nInfixFound++; } } String sPrefixSource; String sDateSource; String sInfixSource; String sTimeSource; String sPostfixSource; // // If there are no occurence of the infix literal, use // use a fixed date and time to generate data based on picture // masks and use their lengths to separate the date data from the time // data. This approach will invariably fail for pictures that specify // variable length symbols. // if (nInfixFound == 0) { // // Construct date and time data from date and time masks. // StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sDateSubMask = new StringBuilder(); StringBuilder sTimeSubMask = new StringBuilder(); isSubPicture(sDateMask, 0, sCategory, sLoc, sDateSubMask); LcDate oToday = new LcDate(1, sLoc.toString(), LcDate.DEFAULT_CENTURY_SPLIT); String sDateMaskData = oToday.format(sDateSubMask.toString()); sLoc.replace(0, sLoc.length(), sLocale); isSubPicture(sTimeMask, 0, sCategory, sLoc, sTimeSubMask); LcTime oNow = new LcTime(LcTime.MILLISPERHOUR + LcTime.MILLISPERMINUTE + LcTime.MILLISPERSECOND + 1, sLoc.toString()); String sTimeMaskData = oNow.format(sTimeSubMask.toString()); // // Apply mask data lengths to the source data to extract // any prefix, infix and postfix literals, the // date source data, and the time source data. // int nDateSourceStart, nTimeSourceStart, nPostfixSourceStart; if (bDateFirst) { nDateSourceStart = sPrefixMaskData.length(); nInfixSourceStart = nDateSourceStart + sDateMaskData.length(); nTimeSourceStart = nInfixSourceStart + sInfixMaskData.length(); nPostfixSourceStart = nTimeSourceStart + sTimeMaskData.length(); } else { nTimeSourceStart = sPrefixMaskData.length(); nInfixSourceStart = nTimeSourceStart + sTimeMaskData.length(); nDateSourceStart = nInfixSourceStart + sInfixMaskData.length(); nPostfixSourceStart = nDateSourceStart + sDateMaskData.length(); } { Point p=resolveRange(sSource, 0, sPrefixMaskData.length()); sPrefixSource = sSource.substring(p.x,p.y); } { Point p=resolveRange(sSource, nDateSourceStart, nDateSourceStart + sDateMaskData.length()); sDateSource = sSource.substring(p.x,p.y); } { Point p=resolveRange(sSource, nInfixSourceStart, nInfixSourceStart + sInfixMaskData.length()); sInfixSource = sSource.substring(p.x,p.y); } { Point p=resolveRange(sSource, nTimeSourceStart, nTimeSourceStart + sTimeMaskData.length()); sTimeSource = sSource.substring(p.x,p.y); } { Point p=resolveRange(sSource, nPostfixSourceStart, sSource.length()); sPostfixSource = sSource.substring(p.x,p.y); } // // Having separated the 5 possible components of a datetime value, // do check each individually. // if (! sPrefixSource.equals(sPrefixMaskData)) return false; if (! sPostfixSource.equals(sPostfixMaskData)) return false; if (! sInfixSource.equals(sInfixMaskData)) return false; StringHolder sParsedDate = new StringHolder(); if (! parseDate(sDateSource, sDateMask, sLocale, sParsedDate, bAsLocal)) return false; StringHolder sParsedTime = new StringHolder(); if (! parseTime(sTimeSource, sTimeMask, sLocale, sParsedTime, bAsLocal)) return false; sResult.value = sParsedDate.value + 'T' + sParsedTime.value; return true; } // // Otherwise For each occurence of the infix literal Do use it // to separate the date data from the time data. // else { int nAt; for (int nStart = 0; (nAt = sSource.indexOf(sInfixMaskData, nStart)) >= 0; nStart = nAt + sInfixMaskData.length()) { nInfixSourceStart = nAt; int nDateSourceStart, nTimeSourceStart, nPostfixSourceStart; nPostfixSourceStart = sSource.length() - sPostfixMaskData.length(); if (bDateFirst) { nDateSourceStart = sPrefixMaskData.length(); { Point p=resolveRange(sSource, nDateSourceStart, nInfixSourceStart); sDateSource = sSource.substring(p.x,p.y); } nTimeSourceStart = nInfixSourceStart + sInfixMaskData.length(); { Point p=resolveRange(sSource, nTimeSourceStart, nPostfixSourceStart); sTimeSource = sSource.substring(p.x,p.y); } } else { nTimeSourceStart = sPrefixMaskData.length(); { Point p=resolveRange(sSource, nTimeSourceStart, nInfixSourceStart); sTimeSource = sSource.substring(p.x,p.y); } nDateSourceStart = nInfixSourceStart + sInfixMaskData.length(); { Point p=resolveRange(sSource, nDateSourceStart, nPostfixSourceStart); sDateSource = sSource.substring(p.x,p.y); } } { Point p=resolveRange(sSource, 0, sPrefixMaskData.length()); sPrefixSource = sSource.substring(p.x,p.y); } { Point p=resolveRange(sSource, nInfixSourceStart, nInfixSourceStart + sInfixMaskData.length()); sInfixSource = sSource.substring(p.x,p.y); } { Point p=resolveRange(sSource, nPostfixSourceStart, sSource.length()); sPostfixSource = sSource.substring(p.x,p.y); } // // Now having separated the 5 possible components // of a datetime value, do check each individually. // if (! sPrefixSource.equals(sPrefixMaskData)) continue; if (! sPostfixSource.equals(sPostfixMaskData)) continue; if (! sInfixSource.equals(sInfixMaskData)) continue; StringHolder sParsedDate = new StringHolder(); if (! parseDate(sDateSource, sDateMask, sLocale, sParsedDate, bAsLocal)) continue; StringHolder sParsedTime = new StringHolder(); if (! parseTime(sTimeSource, sTimeMask, sLocale, sParsedTime, bAsLocal)) continue; sResult.value = sParsedDate.value + 'T' + sParsedTime.value; return true; } } return false; } /** * Parses a given data source according to the given null picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the null picture. * @param sLocale * the locale name. * @param sResult * the resulting canonical string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean parseNull(String sSource, String sPicture, String sLocale, StringHolder sResult) { sResult.value = ""; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sNullMask= new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sNullMask) && ! sCategory.toString().equals(gsNull)) { sNullMask.replace(0, sNullMask.length(), sPicture); } LcNum oNum = new LcNum(sSource, sNullMask.toString(), sLoc.toString()); if (oNum.isValid()) sResult.value = null; return sResult.value == null; } /** * Parses a given data source according to the given numeric picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the numeric picture. * @param sLocale * the locale name. * @param sResult * the resulting canonical string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean parseNumeric(String sSource, String sPicture, String sLocale, StringHolder sResult) { if (!StringUtils.isEmpty(sResult.value)) sResult.value = ""; //sResult.value = ""; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sNumMask= new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sNumMask) && ! sCategory.toString().equals(gsNum)) { sNumMask.replace(0, sNumMask.length(), sPicture); } LcNum oNum = new LcNum(sSource, sNumMask.toString(), sLoc.toString()); if (oNum.isValid()) { sResult.value = oNum.getText(); } return !StringUtils.isEmpty(sResult.value); } /** * Parses a given data source according to the given text picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the text picture. * @param sLocale * the locale name. * @param sResult * the resulting canonical string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean parseText(String sSource, String sPicture, String sLocale, StringHolder sResult) { //sResult.value = ""; if (!StringUtils.isEmpty(sResult.value)) sResult.value = ""; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sTextMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sTextMask) && ! sCategory.toString().equals(gsText)) { sTextMask.replace(0, sTextMask.length(), sPicture); } LcText oText = new LcText(sSource, sTextMask.toString(), sLoc.toString()); if (oText.isValid()) sResult.value = oText.getText(); return !StringUtils.isEmpty(sResult.value); } /** * Parses a given data source according to the given time picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the time picture. * @param sLocale * the locale name. * @param sResult * the resulting canonical string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean parseTime(String sSource, String sPicture, String sLocale, StringHolder sResult, boolean bAsLocal) { //sResult.value = ""; if (!StringUtils.isEmpty(sResult.value)) sResult.value = ""; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sTimeMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sTimeMask) && ! sCategory.toString().equals(gsTime)) { sTimeMask.replace(0, sTimeMask.length(), sPicture); } LcTime oTime = new LcTime(sSource, sTimeMask.toString(), sLoc.toString()); if (oTime.isValid()) { ISOTime oISOTime = new ISOTime(oTime.getMillis()); if (bAsLocal) oISOTime.setLocalTime(); // // Pick format string depending on how specified the time is // if (oISOTime.getMilliSecond() > 0) sResult.value = oISOTime.format("HH:MM:SS.FFF"); else if (oISOTime.getSecond() > 0) sResult.value = oISOTime.format("HH:MM:SS"); else if (oISOTime.getMinute() > 0) sResult.value = oISOTime.format("HH:MM"); else sResult.value = oISOTime.format("HH"); } return !StringUtils.isEmpty(sResult.value); } /** * Parses a given data source according to the given zero picture * under the given locale. * * @param sSource * the source data. * @param sPicture * the zero picture. * @param sLocale * the locale name. * @param sResult * the resulting canonical string, which may be empty upon error. * @return * boolean true upon success and false otherwise. */ public static boolean parseZero(String sSource, String sPicture, String sLocale, StringHolder sResult) { //sResult.value = ""; if (!StringUtils.isEmpty(sResult.value)) sResult.value = ""; StringBuilder sLoc = new StringBuilder(sLocale); StringBuilder sCategory = new StringBuilder(); StringBuilder sZeroMask = new StringBuilder(); if (! hasSubPicture(sPicture, 0, sCategory, sLoc, sZeroMask) && ! sCategory.toString().equals(gsZero)) { sZeroMask.replace(0, sZeroMask.length(), sPicture); } LcNum oNum = new LcNum(sSource, sZeroMask.toString(), sLoc.toString()); if (oNum.isValid() && oNum.getValue() == 0) sResult.value = "0"; return !StringUtils.isEmpty(sResult.value); } private final String msLocale; static final String gsPictureLiterals = "\"' ,-./:?+*$()"; static final String gsNull = "null"; static final String gsZero = "zero"; static final String gsNum = "num"; static final String gsText = "text"; static final String gsDate = "date"; static final String gsTime = "time"; static final String gsDateTime = "datetime"; static final String gsShort = "short"; static final String gsMedium = "medium"; static final String gsLong = "long"; static final String gsFull = "full"; static final String gsDefault = "default"; static final String gsInteger = "integer"; static final String gsDecimal = "decimal"; static final String gsCurrency = "currency"; static final String gsPercent = "percent"; private static int getLiteralSubstr(String sPicture, char cChar, int nCharPos, StringBuilder sLiteral) { assert(cChar == '\''); int nFoundPos = nCharPos; int nPos = 0; int nQuoteBeg = nCharPos; int nQuoteEnd = sPicture.length() - 1; int nStart = nPos = nCharPos; while ((nPos = sPicture.indexOf(cChar, nStart)) >= 0) { if (nPos + 1 == sPicture.length()) break; if (sPicture.charAt(nPos + 1) != cChar) break; nStart = nPos + 2; } if (nPos > nCharPos) { nQuoteEnd = nPos; nFoundPos = nPos + 1; // skip trailing quote. if (sLiteral != null) sLiteral.append(sPicture, nQuoteBeg, nQuoteEnd); } return nFoundPos; } }





  • © 2015 - 2024 Weber Informatics LLC | Privacy Policy