com.adobe.xfa.ut.LcText Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*
* ADOBE CONFIDENTIAL
*
* Copyright 2002 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;
/**
* LcText defines objects in support
* of XFA text picture patterns.
*
* Text picture patterns are used to parse and format
* text strings. Here are the metasymbols that form valid
* text picture patterns:
*
* - 9
- a single numeric character.
*
- A
- a single alphabetic character.
*
- O
- a single alphanumeric character.
*
- X
- a single character.
*
-
*
*
* Here's a snippet of code illustrating the use of
* {@link LcText} to reformat a text string
*
* import com.adobe.xfa.ut.LcNum;
* ...
* LcText text = new LcText("Agent 007", "'Agent '999");
* if (text.isValid())
* String s = text.format("999' bottles of beer ...'");
* text = new LcText("Ben-Vindo a Cozumel.",
* "'Ben-Vindo a 'AAAAAAA.", "es_MX");
* if (text.isValid())
* String s = text.format("'Playa ' XXXXXXX");
*
*
* @author Mike P. Tardif
*
* @exclude from published api.
*/
public class LcText {
/**
* LcText pattern symbols: 9AO0X.
*/
public static final String TEXT_PICTURE_SYMBOLS = "9AO0Xt";
/**
* The text's locale.
*/
private final LcLocale mLocale;
/**
* The validity of this text.
*/
private boolean mbValid;
/**
* The parsed text.
*/
private StringBuilder msText;
// JavaPort: Never referenced
// /**
// * The text's locale sensitive symbols.
// */
// private Symbols mSymbols = new Symbols();
/**
* The parsed number of characters.
*/
private int mnSignf;
// JavaPort: Never referenced
// /**
// * An inner class to represent locale sensitive
// * text symbols.
// */
// private static class Symbols {
// char zeroDigit;
// }
/**
* Instantiates an LcText object from the given text
* and in the locale given.
* @param text
* a text string.
* @param locale
* a locale name. When empty, it will default
* to the default locale.
*/
public LcText(String text, String locale) {
String sLocale = StringUtils.isEmpty(locale) ? LcLocale.getLocale() : locale;
LcLocale lcLocale = new LcLocale(sLocale);
mLocale = lcLocale.isValid() ? lcLocale : new LcLocale(LcLocale.DEFAULT_LOCALE);
setTextSymbols(mLocale.getIsoName());
msText = new StringBuilder(text != null ? text : "");
mbValid = true;
}
/**
* Instantiates an LcText object from the given text in the pattern
* given and in the locale given.
* @param text
* a text string.
* @param pat
* a text pattern string used to parse the given text.
* @param locale
* a locale name. When empty, it will default
* to the default locale.
*/
public LcText(String text, String pat, String locale) {
this(text, locale);
mbValid = parse(msText.toString(), pat);
}
/**
* Formats this object according to given text pattern string.
* @param pat
* a text pattern string.
* @return
* the text string formatted according to the given pattern
* string, upon success, and the empty string, upon error.
*/
public String format(String pat) {
if (! mbValid)
return "";
StringBuilder sRes = new StringBuilder();
try {
char prevChr = 0;
int chrCnt = 0;
boolean inQuoted = false;
boolean inQuoteQuoted = false;
//
// Foreach each character of the picture Do ...
//
int picLen = pat.length();
int txtLen = msText.length();
int txtIdx = 0;
for (int i = 0; i < picLen; ) {
int idx = 0;
char chr = pat.charAt(i++);
//
// If seen a quote within a quoted string ...
//
if (inQuoteQuoted) {
if (chr == '\'') { // cases like '...''
sRes.append(chr);
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;
}
else { // cases like '...X
sRes.append(chr);
}
chrCnt++;
}
//
// Elif start of a quoted string ...
//
else if (chr == '\'') {
if (chrCnt > 0) { // cases like ...X'
StringBuilder s = new StringBuilder();
idx = subFormat(prevChr, chrCnt, txtIdx, s);
if (s.length() == 0)
return "";
sRes.append(s);
txtIdx = idx;
chrCnt = 0;
prevChr = 0;
}
inQuoted = true;
}
//
// Elif start of a metacharacter ...
//
else if (DateTimeUtil.matchChr(TEXT_PICTURE_SYMBOLS, chr)
|| ('a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z')) {
if (chr != prevChr) {
if (chrCnt > 0) { // cases like AAX
StringBuilder s = new StringBuilder();
idx = subFormat(prevChr, chrCnt, txtIdx, s);
if (s.length() == 0)
return "";
sRes.append(s);
txtIdx = idx;
chrCnt = 0;
}
prevChr = chr;
}
chrCnt++;
}
//
// Elif start of a literal ...
//
else {
if (chrCnt > 0) { // cases like AA-
StringBuilder s = new StringBuilder();
idx = subFormat(prevChr, chrCnt, txtIdx, s);
if (s.length() == 0)
return "";
sRes.append(s);
txtIdx = idx;
chrCnt = 0;
}
prevChr = 0;
if (chr == '?' || chr == '*' || chr == '+')
sRes.append(' ');
else
sRes.append(chr);
}
}
//
// Ensure quoted string is terminated.
//
if (inQuoteQuoted)
inQuoted = false;
if (inQuoted)
return "";
//
// Format any remaining items in the picture.
//
if (prevChr > 0 && chrCnt > 0) {
//
// Ensure there's enough source to format
// Subtract the number of processed characters
// from the total number of characters in the
// source string.
//
int numSrcCharsLeft = txtLen - txtIdx;
if (numSrcCharsLeft < chrCnt)
return "";
StringBuilder s = new StringBuilder();
int idx = subFormat(prevChr, chrCnt, txtIdx, s);
if (s.length() == 0)
return "";
sRes.append(s);
txtIdx = idx;
}
//
// Ensure there's no more source to format.
//
if (txtIdx != 0 && txtIdx != txtLen)
return "";
}
catch(ExFull e) {
sRes.setLength(0);
}
return sRes.toString();
}
/**
* Parse the text picture and return the number of symbols the picture implies.
* @param pic - a picture pattern string.
*/
public static int getSymbolCount(String pic) {
String sLoc = LcLocale.English_US;
LcText oText = new LcText("", sLoc);
oText.xlate(pic);
return oText.mnSignf;
}
/**
* Gets this object's parsed text.
* @return
* the text associated with this object.
*/
public String getText() {
return msText.toString();
}
/**
* Determines if this object is valid.
* @return
* boolean true if valid, and false otherwise.
*/
public boolean isValid() {
return mbValid;
}
/**
* Parses the given string according to the text pattern given.
* @param str
* the text string to parse.
* @param pat
* a text pattern string.
* @return
* boolean true if successfully parsed, and false otherwise.
*/
public boolean parse(String str, String pat) {
mbValid = false;
int strPos = 0;
char prevChr = 0;
int chrCnt = 0;
boolean inQuoted = false;
boolean inQuoteQuoted = false;
int strLen = str.length();
int picLen = pat.length();
StringBuilder sRes = new StringBuilder();
int resPos;
//
// Foreach each character of the picture Do ...
//
for (int i = 0; i < picLen; ) {
char chr = pat.charAt(i++);
if (strPos >= strLen) {
if (inQuoted && chr == '\'') {
inQuoteQuoted = true;
break;
}
return false;
}
//
// If seen a quote within a quoted string ...
//
if (inQuoteQuoted) {
if (chr == '\'') { // cases like '...''
if (! DateTimeUtil.matchChr(str, strPos, chr, false))
return false;
strPos += 1;
chrCnt = 0;
}
else { // cases like '...'A
inQuoted = false;
chrCnt = 1;
prevChr = chr;
}
inQuoteQuoted = false;
}
//
// Elif within a quoted string ...
//
else if (inQuoted) {
if (chr == '\'') { // cases like '...'
inQuoteQuoted = true;
}
else { // cases like '...A
if (! DateTimeUtil.matchChr(str, strPos, chr, false))
return false;
strPos += 1;
}
chrCnt++;
}
//
// Elif start of a quoted string ...
//
else if (chr == '\'') {
if (chrCnt > 0) { // cases like AA'
resPos = subParse(str, strPos, prevChr, chrCnt);
if (resPos < 0)
return false;
if (DateTimeUtil.matchChr(TEXT_PICTURE_SYMBOLS, prevChr))
sRes.append(getStr(str, strPos, resPos));
strPos = resPos;
chrCnt = 0;
prevChr = 0;
}
inQuoted = true;
}
//
// Elif start of a metacharacter ...
//
else if (DateTimeUtil.matchChr(TEXT_PICTURE_SYMBOLS, chr)
|| ('a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z')) {
if (chr != prevChr) {
if (chrCnt > 0) { // cases like AAX
resPos = subParse(str, strPos, prevChr, chrCnt);
if (resPos < 0)
return false;
if (DateTimeUtil.matchChr(TEXT_PICTURE_SYMBOLS, prevChr))
sRes.append(getStr(str, strPos, resPos));
strPos = resPos;
chrCnt = 0;
}
prevChr = chr;
}
chrCnt++;
}
//
// Elif start of a literal ...
//
else {
if (chrCnt > 0) { // cases like AA-
resPos = subParse(str, strPos, prevChr, chrCnt);
if (resPos < 0)
return false;
if (DateTimeUtil.matchChr(TEXT_PICTURE_SYMBOLS, prevChr))
sRes.append(getStr(str, strPos, resPos));
strPos = resPos;
chrCnt = 0;
prevChr = 0;
}
if (chr == '?') {
if (strPos < strLen && Character.isDefined(str.charAt(strPos)))
strPos += 1;
}
else if (chr == '+') {
if (strPos >= strLen
|| ! Character.isWhitespace(str.charAt(strPos)))
return false;
strPos += 1;
while (strPos < strLen
&& Character.isWhitespace(str.charAt(strPos)))
strPos += 1;
}
else if (chr == '*') {
while (strPos < strLen
&& Character.isWhitespace(str.charAt(strPos)))
strPos += 1;
}
else if (strPos < strLen && str.charAt(strPos) == chr) {
strPos += 1;
}
else {
return false;
}
}
}
//
// Ensure quoted string is terminated.
//
if (inQuoteQuoted)
inQuoted = false;
if (inQuoted)
return false;
//
// Parse any remaining items in the picture.
//
if (prevChr > 0 && chrCnt > 0) {
//
// Ensure there's enough source to format
// Subtract the number of processed characters
// from the total number of characters in the
// source string.
//
int numSrcCharsLeft = strLen-strPos;
if (numSrcCharsLeft < chrCnt)
return false;
resPos = subParse(str, strPos, prevChr, chrCnt);
if (resPos < 0)
return false;
if (DateTimeUtil.matchChr(TEXT_PICTURE_SYMBOLS, prevChr))
sRes.append(getStr(str, strPos, resPos));
strPos = resPos;
}
//
// Ensure there's no more source to parse.
//
if (strPos != strLen)
return false;
msText = sRes;
return true;
}
/*
* Gets a (previously matched) number of characters
* from a given start position
* to a given end position of the given string.
*
* @param src
* the string to parse.
* @param begPos
* the beginning parsing position within the string.
* @param endPos
* the ending parsing position within the string.
* @return
* the characters matched.
*/
private String getStr(String src, int begPos, int endPos) {
assert(begPos < endPos && endPos <= src.length());
StringBuilder s = new StringBuilder();
while (begPos < endPos)
s.append(src.charAt(begPos++));
return s.toString();
}
/*
* Matches a number of alphabetics from a given start position
* to a given end position of the given string.
*
* @param src
* the string to parse.
* @param begPos
* the beginning parsing position within the string.
* @param endPos
* the ending parsing position within the string.
* @return
* the number of alphabetics matched, or -1 otherwise.
*/
private int matchAlphabetic(String src, int begPos, int endPos) {
assert(begPos < endPos && endPos <= src.length());
boolean bAlphasSeen = false;
int nAlphasSeen = 0;
while (begPos < endPos) {
char cUni = src.charAt(begPos++);
if (! Character.isLetter(cUni))
break;
bAlphasSeen = true;
nAlphasSeen++;
}
return (bAlphasSeen) ? nAlphasSeen : -1;
}
/*
* Matches a number of alphanumerics from a given start position
* to a given end position of the given string.
*
* @param src
* the string to parse.
* @param begPos
* the beginning parsing position within the string.
* @param endPos
* the ending parsing position within the string.
* @return
* the number of alphanumerics matched, or -1 otherwise.
*/
private int matchAlphanumeric(String src, int begPos, int endPos) {
assert(begPos < endPos && endPos <= src.length());
boolean bAlphanumsSeen = false;
int nAlphanumsSeen = 0;
while (begPos < endPos) {
char cUni = src.charAt(begPos++);
if (! Character.isLetterOrDigit(cUni))
break;
bAlphanumsSeen = true;
nAlphanumsSeen++;
}
return (bAlphanumsSeen) ? nAlphanumsSeen : -1;
}
/*
* Matches a number of characters from a given start position
* to a given end position of the given string.
*
* @param src
* the string to parse.
* @param begPos
* the beginning parsing position within the string.
* @param endPos
* the ending parsing position within the string.
* @return
* the number of characters matched, or -1 otherwise.
*/
private int matchCharacter(String src, int begPos, int endPos) {
assert(begPos < endPos && endPos <= src.length());
boolean bCharsSeen = false;
int nCharsSeen = 0;
while (begPos < endPos) {
char cUni = src.charAt(begPos++);
if (! Character.isDefined(cUni))
break;
bCharsSeen = true;
nCharsSeen++;
}
return (bCharsSeen) ? nCharsSeen : -1;
}
/*
* Match a number of numerics from a given start position
* to a given end position of the given string.
*
* @param src
* the string to parse.
* @param begPos
* the beginning parsing position within the string.
* @param endPos
* the ending parsing position within the string.
* @return
* the number of digits matched, or -1 otherwise.
*/
private int matchNumeric(String src, int begPos, int endPos) {
assert(begPos < endPos && endPos <= src.length());
boolean bDigitsSeen = false;
int nDigitsSeen = 0;
while (begPos < endPos) {
char cUni = src.charAt(begPos++);
if (! Character.isDigit(cUni))
break;
bDigitsSeen = true;
nDigitsSeen++;
}
return (bDigitsSeen) ? nDigitsSeen : -1;
}
/*
* Sets locale-specific text symbols for the given locale.
* @param locale
* a locale name. When empty, it will default
* to the default locale.
*/
private void setTextSymbols(String locale) {
//LcData oData = new LcData(locale);
//mSymbols.zeroDigit = oData.getZeroSymbol().charAt(0);
}
/*
* Formats a sub-element of a text pattern given the number of
* occurances of a text pattern metacharacter.
*
* @param chr
* a text pattern metacharacter.
* @param chrCnt
* the number of consecutive occurances of the metacharacter.
* @param txtIdx
* an index into this object's text string.
* @param sRes
* the formatted sub-element, or the empty upon error.
* @return
* the index into this object's text string.
* @throws
* an ExFull if the text value overflowed the field.
*/
private int subFormat(char chr, int chrCnt, int txtIdx, StringBuilder sRes) {
assert(sRes != null);
int retIdx = 0;
int txtLen = msText.length();
while (chrCnt-- > 0 && txtIdx < txtLen) {
char cUni;
switch (chr) {
case '9': // Numeric
cUni = msText.charAt(txtIdx++);
if (! Character.isDigit(cUni))
throw new ExFull();
sRes.append(cUni);
break;
case 'A': // Alphebetic
cUni = msText.charAt(txtIdx++);
if (! Character.isLetter(cUni))
throw new ExFull();
sRes.append(cUni);
break;
case 'O': // Alphanumeric
case '0':
cUni = msText.charAt(txtIdx++);
if (! Character.isLetterOrDigit(cUni))
throw new ExFull();
sRes.append(cUni);
break;
case 'X': // Anything
cUni = msText.charAt(txtIdx++);
sRes.append(cUni);
break;
case 't':
sRes.append('\t');
break;
default:
sRes.append(chr);
break;
}
retIdx = txtIdx;
}
return retIdx;
}
/*
* Parses a sub-element at a given position of the given string,
* given the number of occurrences of a text pattern metacharacter.
*
* @param src
* the text string to parse.
* @param srcPos
* the starting parsing position within the text string.
* @param chr
* a text pattern metacharacter.
* @param chrCnt
* the number of consecutive occurances of the metacharacter.
* @return
* the ending parsing position within the text string
* if successfully parsed, and -1 otherwise.
*/
private int subParse(String src, int srcPos, char chr, int chrCnt) {
int len;
switch (chr) {
case '9': // Numeric
len = matchNumeric(src, srcPos, srcPos + chrCnt);
if (len != chrCnt)
return -1;
srcPos = DateTimeUtil.incPos(src, srcPos, len);
break;
case 'A': // Alphebetic
len = matchAlphabetic(src, srcPos, srcPos + chrCnt);
if (len != chrCnt)
return -1;
srcPos = DateTimeUtil.incPos(src, srcPos, len);
break;
case 'O': // Alphanumeric
case '0':
len = matchAlphanumeric(src, srcPos, srcPos + chrCnt);
if (len != chrCnt)
return -1;
srcPos = DateTimeUtil.incPos(src, srcPos, len);
break;
case 'X': // Anything
len = matchCharacter(src, srcPos, srcPos + chrCnt);
if (len != chrCnt)
return -1;
srcPos = DateTimeUtil.incPos(src, srcPos, len);
break;
case 't': // tab
while (chrCnt-- > 0) {
if (src.charAt(srcPos) != '\t')
return -1;
srcPos += 1;
}
break;
default:
if (src.charAt(srcPos) != chr)
return -1;
srcPos += 1;
break;
}
return srcPos;
}
/*
* Translate a sub-element of a text pattern given the number of
* occurrences of a text pattern meta-character.
*
* Parameters:
* chr -- a text pattern meta-character.
* chrCnt -- the number of consecutive occurrences of the meta-character.
*
* Return Value:
* the translated sub-element, or the empty string upon error.
*
* Exceptions:
* jfExFull if sub-elements aren't translated in the proper
* sequence.
*/
private String subXlate(char chr, int chrCnt) {
StringBuilder sRes = new StringBuilder();
for (int i = 0; i < chrCnt; i++)
sRes.append(chr);
//
// Re-map any full width meta symbol back to ASCII.
//
if (0xFF01 <= chr && chr <= 0xFF5E) {
chr -= 0xFFE0;
chr &= 0x00FF;
}
if (chr == '9' || chr == 'A' || chr == 'O' || chr == '0' || chr == 'X') {
mnSignf += chrCnt;
}
return sRes.toString();
}
/*
* Translate a text picture pattern into something else .easily
* In the process, flag:
* the number of significant digits,
*
* Parameters:
* pic -- a text picture pattern.
*
* Return Value:
* the translated picture.
*
* Exceptions:
* jfExFull if the picture pattern is not valid.
*/
private String xlate(String pic) {
//
// Reset the state formatting flags.
//
mnSignf = 0;
//
// Initialize finite state scanner. Only operate on previous
// character when there's a "state" change triggered by the
// current pattern character.
//
String sRes = null;
char prevChr = 0;
int chrCnt = 0;
boolean inQuoted = false;
boolean inQuoteQuoted = false;
//
// For each character of the pattern Do ...
//
int picLen = pic.length();
for (int i = 0; i < picLen; ) {
char chr = pic.charAt(i++);
//
// If seen a quote within a quoted string ...
//
if (inQuoteQuoted) {
if (chr == '\'') { // cases like '...''
sRes += chr;
chrCnt = 0;
}
else { // cases like '...'9
inQuoted = false;
chrCnt = 1;
prevChr = chr;
}
inQuoteQuoted = false;
}
//
// Else if within a quoted string ...
//
else if (inQuoted) {
if (chr == '\'') // cases like '...'
inQuoteQuoted = true;
sRes += chr;
chrCnt = 0;
prevChr = chr;
}
//
// Else if start of a quoted string ...
//
else if (chr == '\'') {
if (chrCnt > 0) { // cases like ...9'
sRes += subXlate(prevChr, chrCnt);
chrCnt = 0;
prevChr = 0;
}
sRes += chr;
inQuoted = true;
}
//
// Else if its a meta-character ...
//
else if (DateTimeUtil.matchChr(TEXT_PICTURE_SYMBOLS, chr)
|| ('a' <= chr && chr <= 'z' || 'A' <= chr && chr <= 'Z')) {
if (prevChr != chr) {
if (chrCnt > 0) { // cases like ZZ9 or :9
sRes += subXlate(prevChr, chrCnt);
prevChr = chr;
chrCnt = 1;
}
else {
prevChr = chr;
chrCnt++;
}
}
else {
chrCnt++;
}
}
//
// Else if start of a literal ...
//
else {
if (chrCnt > 0) { // cases like 99-
sRes += subXlate(prevChr, chrCnt);
chrCnt = 0;
}
prevChr = 0;
sRes += chr;
}
}
//
// Ensure quoted string is terminated.
//
if (inQuoteQuoted)
inQuoted = false;
if (inQuoted)
throw new ExFull();
//
// Format any remaining items in the pattern.
//
if (prevChr > 0 && chrCnt > 0)
sRes += subXlate(prevChr, chrCnt);
return sRes;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy