/* XBN Java: Generically useful, non-GUI Java code. http://sourceforge.net/projects/xbnjava Copyright (C) 1997-2003, Jeff Epstein All rights reserved. Modifications: No Redistribution in binary form, with or without modifications, are permitted provided that the following conditions are met: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * If modifications are made to source code then this license should indicate that fact in the "Modifications" section above. * Neither the author, nor the contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [NOTE: This license contains NO advertising clause.] */ package xbn.string; import xbn.XBNObject; import xbn.array.primitive.PARDupNullLen; import xbn.array.primitive.PARString; import xbn.array.primitive.PAViolation; import xbn.placeholder.i_i; import xbn.placeholder.i_i_i; import xbn.placeholder.i_i_i_i; import xbn.util.RCLength; /**

Random functions for StringOrBuffers. See StringOrBuffer.

Source code:  UtilSOB.java.  Unit tests:  xbn_junit.JUTUtilSOB.java.

@version 0.9b @author Jeff Epstein, http://sourceforge.net/projects/xbnjava. **/ public class UtilSOB extends XBNObject { //ENTIRE strings used four or more times. private i_i_i_i iiiiGSAInfo = null; /**

To shorten code and Javadoc.

Equal to "xbn.string.UtilSOB"

**/ public static final String sUSOB = "xbn.string.UtilSOB"; private UtilChar uChar = new UtilChar(); private final StringOrBuffer[] asobForCrashIfXInY = new StringOrBuffer[2]; /**

Create a UtilSOB. This constructor does nothing.

**/ public UtilSOB() { } /**

Find the first occurance of the search string, where it is an entire word (not part of a larger word).

@return indexOfWord(str_orBfr, s_searchWord, i_idxLeft, i_idxAfterRight, true) **/ public final int indexOfWord(StringOrBuffer str_orBfr, String s_searchWord, int i_idxLeft, int i_idxAfterRight) { return indexOfWord(str_orBfr, s_searchWord, i_idxLeft, i_idxAfterRight, true); } /**

Find the left-most occurance of the search string, where it is an entire word (not part of a larger word).

@param str_orBfr The StringOrBuffer in which to search for s_searchWord. Provided directly to str_orBfr.indexOf. @param i_idxLeft The left-most index to search. Provided directly to str_orBfr.indexOf. @param i_idxAfterRight The index after the right-most index to search. Provided directly to str_orBfr.indexOf. @param b_bounded Should the search string be bounded within i_idxLeft and i_idxAfterRight? Provided directly to str_orBfr.indexOf. @return Array index indicating the left-most occurance of the search string, when the... **/ public final int indexOfWord(StringOrBuffer str_orBfr, String s_searchWord, int i_idxLeft, int i_idxAfterRight, boolean b_bounded) { return idxLastIdxOfWord(str_orBfr, s_searchWord, i_idxLeft, i_idxAfterRight, b_bounded, true, "indexOfWord"); } /**

Find the last occurance of the search string, where it is an entire word (not part of a larger word).

@return lastIndexOfWord(str_orBfr, s_searchWord, i_idxLeft, i_idxAfterRight, true) **/ public final int lastIndexOfWord(StringOrBuffer str_orBfr, String s_searchWord, int i_idxLeft, int i_idxAfterRight) { return lastIndexOfWord(str_orBfr, s_searchWord, i_idxLeft, i_idxAfterRight, true); } /**

Find the right-most occurance of the search string, where it is an entire word (not part of a larger word).

@param str_orBfr The StringOrBuffer in which to search for s_searchWord. Provided directly to str_orBfr.indexOf. @param i_idxLeft The left-most index to search. Provided directly to str_orBfr.indexOf. @param i_idxAfterRight The index after the right-most index to search. Provided directly to str_orBfr.indexOf. @param b_bounded Should the search string be bounded within i_idxLeft and i_idxAfterRight? Provided directly to str_orBfr.indexOf. @return Array index indicating the right-most occurance of the search string, when the... **/ public final int lastIndexOfWord(StringOrBuffer str_orBfr, String s_searchWord, int i_idxLeft, int i_idxAfterRight, boolean b_bounded) { return idxLastIdxOfWord(str_orBfr, s_searchWord, i_idxLeft, i_idxAfterRight, b_bounded, false, "lastIndexOfWord"); } /**

Get a copy of the StringOrBuffer (as an SOBStringBuffer) where each line is quoted.

@return The contents of getSOBSB: quoteLines(getSOBSB(str_orBfr, "getQuotedLines")) **/ public final StringOrBuffer getQuotedLines(StringOrBuffer str_orBfr) { SOBStringBuffer ssb = getSOBSB(str_orBfr, "getQuotedLines"); quoteLines(ssb); return ssb; } /**

Get a copy of the StringOrBuffer (as an SOBStringBuffer) where each line is quoted.

@return The contents of getSOBSB: quoteLines(getSOBSB(str_orBfr, "getQuotedLines"), s_quote) **/ public final StringOrBuffer getQuotedLines(StringOrBuffer str_orBfr, String s_quote) { SOBStringBuffer ssb = getSOBSB(str_orBfr, "getQuotedLines"); quoteLines(ssb, s_quote); return ssb; } /**

Get a copy of the StringOrBuffer (as an SOBStringBuffer) where each line is quoted.

@return The contents of getSOBSB: quoteLines(getSOBSB(str_orBfr, "getQuotedLines"), s_quoteStart, s_quoteEnd) **/ public final StringOrBuffer getQuotedLines(StringOrBuffer str_orBfr, String s_quoteStart, String s_quoteEnd) { SOBStringBuffer ssb = getSOBSB(str_orBfr, "getQuotedLines"); quoteLines(ssb, s_quoteStart, s_quoteEnd); return ssb; } /**

Get a copy of the StringOrBuffer (as a StringBuffer) where each line is quoted.

@return The contents of getSOBSB: quoteLines(getSOBSB(str_orBfr, "getQuotedLines"), s_quoteStart, s_quoteEnd, s_lineSep) **/ public final StringOrBuffer getQuotedLines(StringOrBuffer str_orBfr, String s_quoteStart, String s_quoteEnd, String s_lineSep) { SOBStringBuffer ssb = getSOBSB(str_orBfr, "getQuotedLines"); quoteLines(ssb, s_quoteStart, s_quoteEnd, s_lineSep); return ssb; } /**

Quote each line within the StringOrBuffer.

Equal to quoteLines(str_orBfr, "'")

**/ public final void quoteLines(StringOrBuffer str_orBfr) { quoteLines(str_orBfr, "'"); } /**

Quote each line within the StringOrBuffer.

Equal to quoteLines(str_orBfr, s_quote, s_quote)

**/ public final void quoteLines(StringOrBuffer str_orBfr, String s_quote) { quoteLines(str_orBfr, s_quote, s_quote); } /**

Quote each line within the StringOrBuffer.

Equal to quoteLines(str_orBfr, s_quoteStart, s_quoteEnd, sLINE_SEP)

**/ public final void quoteLines(StringOrBuffer str_orBfr, String s_quoteStart, String s_quoteEnd) { quoteLines(str_orBfr, s_quoteStart, s_quoteEnd, sLINE_SEP); } /**

Quote each line within the StringOrBuffer. Intended for display purposes only, to emphasize the tabs and spaces existing at the ends of each line. See TrimChars.trimAllLines and makeVisible.

@param str_orBfr The StringOrBuffer to get a quoted copy of. May not be null. @param s_quoteStart . The quote to put at the beginning of each line. May not be null or zero characters in length. @param s_quoteEnd The quote to put at the end of each line. May not be null or zero characters in length. @param s_lineSep Whatever you define the line separator to be. May not be null or zero characters in length. **/ public final void quoteLines(StringOrBuffer str_orBfr, String s_quoteStart, String s_quoteEnd, String s_lineSep) { //This is basically a simplified version of trimAllLines. throwAXIfBadStr(s_quoteStart, "s_quoteStart", "quoteLines"); throwAXIfBadStr(s_quoteEnd, "s_quoteEnd", "quoteLines"); throwAXIfBadStr(s_lineSep, "s_lineSep", "quoteLines"); int i = 0; while(i <= str_orBfr.length()) { str_orBfr.insert(i, s_quoteStart); while(i < str_orBfr.length() && !str_orBfr.isStringAt(s_lineSep, i)) { //We've not yet reached the end of this line, nor the end of //str_orBfr. i++; } //We are now either at the end of this line, or the end of the //str_orBfr. if(i >= str_orBfr.length()) { //This is the end of the str_orBfr. str_orBfr.append(s_quoteEnd); break; } //We are now at the first character in the line separator, at //the end of this line. //Quote the end of this line. str_orBfr.insert(i, s_quoteEnd); //Go to the first character in the next line. //Go to the first character after the line separator. i += (s_lineSep.length() + s_quoteEnd.length()); if(i >= str_orBfr.length()) { //This is the end of the str_orBfr. There are no //more lines. //This str_orBfr ends with a line separator. So the //last line is an empty string. str_orBfr.append(s_quoteStart + s_quoteEnd); break; } } } /**

Get a string surrounding the provided character index, having specific delimiters.

For information regarding the call just made to this function, see getGSAInfo.

@param str_orBfr The string to get the substring from. May not be null, and must be long enough such that all these conditions are met:
  1. str_orBfr.indexOf(s_delimLeft) may not equal -1 and the index of the last character in s_delimLeft must equal [i_charIdx - 1] or less. Exception: It is legal for the left delimiter to not exist if b_sosAltLeftDelim equals true.
  2. str_orBfr.indexOf(s_delimRight) may not equal -1 and the index of the first character in s_delimRight must equal i_charIdx or greater. Exception: It is legal for the right delimiter to not exist if b_sosAltRightDelim equals true.
  3. i_charIdx must be a legal character array index for str_orBfr.
@param i_charIdx The character index existing somewhere within str_orBfr, and between s_delimLeft and s_delimRight. @param s_delimLeft The left delimiter, defining the start of the string to be returned. May not be null, or zero characters in length. The left delimiter closest to i_charIdx (on the left) is used. @param s_delimRight The right delimiter, defining the end of the string to be returned. May not be null, or zero characters in length. The left delimiter closest to i_charIdx (on the right) is used. @param b_endsOfStrAltDelims If s_delimLeft does not exist before, and/or s_delimRight does not after i_charIdx, is the start/end of the string (index str_orBfr.length) a legal substitute for s_delimLeft/s_delimRight? If true and s_delimLeft/s_delimRight does not exist, then the start/end of the string is the delimiter. If false, then both s_delimLeft and s_delimRight are required to exist. @param b_includeDelimiters Should s_delimLeft and s_delimRight be included in the string that is returned? If true, yes (when b_eosAltRightDelim equals true, the left and right delimiters are included only if they exist). If false, no. @return For example. Say...

Value of Value of getGSAInfo(]...
b_endsOfStrAltDelims b_includeDelimiters Returned value .i1 .i2 .i3 .i4
false false http://sourceforge.net/projects/xbnjava 8 9 34 34
false true "http://sourceforge.net/projects/xbnjava" 8 8 34 35

Say...

Value of Value of getGSAInfo(]...
b_endsOfStrAltDelims b_includeDelimiters Returned value .i1 .i2 .i3 .i4
true true <A HREF=http://sourceforge.net/projects/xbnjava" 8 0 34 35
true false <A HREF=http://sourceforge.net/projects/xbnjava 8 0 34 34
false true AssertException n/a

**/ public final String getStringAround(StringOrBuffer str_orBfr, int i_charIdx, String s_delimLeft, String s_delimRight, boolean b_endsOfStrAltDelims, boolean b_includeDelimiters) { throwAXIfBadStr(s_delimLeft, "s_delimLeft", "getStringAround"); throwAXIfBadStr(s_delimRight, "s_delimRight", "getStringAround"); iiiiGSAInfo = new i_i_i_i(); int iLeftDelim = -1; try { iLeftDelim = str_orBfr.lastIndexOf(s_delimLeft, 0, i_charIdx); iiiiGSAInfo.i1 = iLeftDelim; } catch(NullPointerException npx) { iiiiGSAInfo = null; throwAX("getStringAround: str_orBfr is null."); } catch(IndexOutOfBoundsException ioobx) { iiiiGSAInfo = null; throwAX("getStringAround: i_charIdx (" + i_charIdx + ") is illegal. str_orBfr.length()=" + str_orBfr.length() + "."); } if(iLeftDelim == -1) { //The left delimiter was not found... if(!b_endsOfStrAltDelims) { //...and that is bad. iiiiGSAInfo = null; throwAX("getStringAround: b_endsOfStrAltDelims equals false, but s_delimLeft ('" + s_delimLeft + "') does not exist (completely) before i_charIdx (" + i_charIdx + ")."); } else { //...not that there's anything wrong with that! iLeftDelim = 0; } } else if(!b_includeDelimiters) { //The left delimiter was found, and delimiters should //*not* be included in the returned string. iLeftDelim += s_delimLeft.length(); } int iRightDelim = str_orBfr.indexOf(s_delimRight, i_charIdx); iiiiGSAInfo.i3 = iRightDelim; if(iRightDelim == -1) { if(!b_endsOfStrAltDelims) { iiiiGSAInfo = null; throwAX("getStringAround: b_endsOfStrAltDelims equals false, but s_delimRight ('" + s_delimRight + "') does not exist (completely) after or at i_charIdx (" + i_charIdx + ")."); } else { //...not that there's anything wrong with that! iRightDelim = str_orBfr.length(); } } else if(b_includeDelimiters) { //The right delimiter was found, and delimiters *should* //be included in the returned string. iRightDelim += s_delimRight.length(); } iiiiGSAInfo.i2 = iLeftDelim; iiiiGSAInfo.i4 = iRightDelim; return str_orBfr.substring(iLeftDelim, iRightDelim); } /**

What just happened in the just-called getStringAround?. See getStringAround.

@return An i_i_i_i, where...
null If getStringAround was never called, or threw an exception for any reason. **/ public i_i_i_i getGSAInfo() { return iiiiGSAInfo; } /**

If either string is contained in or equal to the other, get information describing the containment.

@return getContainedIdx(sob_x, sob_y, (new GCICTwo())) **/ public final i_i_i getContainedIdxs(StringOrBuffer sob_x, StringOrBuffer sob_y) { return getContainedIdxs(sob_x, sob_y, (new GCICTwo())); } /**

If either string is contained in (or equal to) the other, get information describing the containment.

Equal to getContainedIdxs((new StringOrBuffer[]{sob_x, sob_y}), gcic_two)

The array is created only once, and populated in this function repeatedly.

**/ public final i_i_i getContainedIdxs(StringOrBuffer sob_x, StringOrBuffer sob_y, GCICTwo gcic_two) { asobForCrashIfXInY[0] = sob_x; asobForCrashIfXInY[1] = sob_y; return getContainedIdxs(asobForCrashIfXInY, gcic_two); } /**

If any StringOrBuffer is contained in (or equal to) any other, get information describing the containment.

Equal to getSOBS(a_strOrBfr, (new GCIConfig()))

**/ public final i_i_i getContainedIdxs(StringOrBuffer[] a_strOrBfr) { return getContainedIdxs(a_strOrBfr, (new GCIConfig())); } /**

If any string is contained in any other, get information describing the containment.

@param a_strOrBfr The array of StringOrBuffers to analyze for containment. May not be null or zero elements in length, and no element may be null or zero characters in length. @return null If no containment was detected.
An i_i_i where i1 is the array index of the containing string, i2 is the array index of the contained string, and i3 is the string index of the containing string, at which the first character of the contained string begins. **/ public final i_i_i getContainedIdxs(StringOrBuffer[] a_strOrBfr, GCIConfig gci_config) { try { if(gci_config.getAOSNames() != null && gci_config.getAOSNames().length != a_strOrBfr.length) { throwAX("getContainedIdxs: gci_config.getAOSNames() is not null, but it's length (" + gci_config.getAOSNames().length + ") is not equal to a_strOrBfr (" + a_strOrBfr.length + ")"); } } catch(NullPointerException npx) { throwAXIfNull(a_strOrBfr, "a_strOrBfr", "getContainedIdxs"); throwAXIfNull(gci_config, "gci_config", "getContainedIdxs"); } PASStringOrBuffer passob = new PASStringOrBuffer(a_strOrBfr, new PARString( new PARDupNullLen(gci_config.isEqualOk(), false, (new RCLength(1, -1, false))), gci_config.getPARSCBad())); if(!passob.isValid()) { int iPAVType = passob.getPAViolation().getType(); if(iPAVType == PAViolation.getType_NULL()) { throwAX("getContainedIdxs: a_strOrBfr is zero elements in length."); } if(iPAVType == PAViolation.getType_SLMNT_NULL()) { throwAX("getContainedIdxs: " + getLmntName(passob, gci_config.getAOSNames()) + " is null."); } if(iPAVType == PAViolation.getType_SLMNT_LENGTH()) { throwAX("getContainedIdxs: " + getLmntName(passob, gci_config.getAOSNames()) + " is zero characters in length."); } //The only other possible errors are duplicate and //contained. if(gci_config.getCallingClassFunc() != null) { //Crash throwAX(gci_config.getCallingClassFunc() + ": " + getLmntName(true, passob, gci_config.getAOSNames()) + " ('" + a_strOrBfr[passob.getPAViolation().getIdxFirst()] + "') contains " + (gci_config.isEqualOk()?"or is equal to ":sES) + getLmntName(false, passob, gci_config.getAOSNames()) + " ('" + a_strOrBfr[passob.getPAViolation().getIdxSecond()] + "') at index " + passob.getPAViolation().getContainedAtIdx() + "."); } //Return indexes return new i_i_i( passob.getPAViolation().getIdxFirst(), passob.getPAViolation().getIdxSecond(), passob.getPAViolation().getContainedAtIdx()); } return null; } /**

Is the value of the StringOrBuffer a valid hexidecimal number?. A hex digit only contains digits and (lowercase) letters from a through f.

@param sob_potentialHex The StringOrBuffer analyzed, to see if it is a hexidecimal number. May not be null or zero characters in length. @return isLegal(sob_potentialHex, false, true, UtilChar.getAOCHexLetters())

**/ public boolean isHexidecimal(StringOrBuffer sob_potentialHex) { throwAXIfBadSOB(sob_potentialHex, "sob_potentialHex", "isHexidecimal"); return isLegal(sob_potentialHex, false, true, UtilChar.getAOCHexLetters()); } /**

Does the StringOrBuffer contain only tabs and spaces?

@param sob_potentialHex The StringOrBuffer analyzed, to see if it contains only tab and space characters. May not be null or zero characters in length. @return hasLegalChars(sob_potentialTabSpace, UtilChar.getAOCTabSpace())

**/ public boolean isTabSpace(StringOrBuffer sob_potentialTabSpace) { throwAXIfBadSOB(sob_potentialTabSpace, "sob_potentialTabSpace", "isTabSpace"); return hasLegalChars(sob_potentialTabSpace, UtilChar.getAOCTabSpace()); } /**

Does the StringOrBuffer not contain any tab and space characters?

@param sob_potentialHex The StringOrBuffer analyzed, to see if it contains only non-tab and non-space characters. May not be null or zero characters in length. @return hasNoIllegalChars(str_orBfr, UtilChar.getAOCTabSpace())

**/ public boolean hasNoTabSpace(StringOrBuffer str_orBfr) { throwAXIfBadSOB(str_orBfr, "str_orBfr", "isTabSpace"); return hasNoIllegalChars(str_orBfr, UtilChar.getAOCTabSpace()); } /**

Append a duplicated string onto the StringOrBuffer.

@param sb_appendTo The StringBuffer to append to. May not be null. @param s_toDuplicate The string to duplicate and then append. May not be null or zero characters in length. @param i_dupCount The number of times to duplicate s_toDuplicate. May not be less than zero. If equal to zero, then nothing is appended to sb_appendTo. **/ public final void dupAppend(StringOrBuffer str_orBfr, String s_toDuplicate, int i_dupCount) { throwAXIfBadStr(s_toDuplicate, "s_toDuplicate", "dupAppend"); if(i_dupCount < 0) { throwAX("getDupedStringBuffer: i_dupCount may not be less than zero. Currently " + i_dupCount + "."); } if(i_dupCount == 0) { return; } try { for(int i = 0; i < i_dupCount; i++) { str_orBfr.append(s_toDuplicate); } } catch(NullPointerException npx) { throwAX("dupAppend: str_orBfr is null."); } } /**

Get a copy of the StringOrBuffer (as an SOBStringBuffer), after appending a duplicated string onto it.

@return The contents of getSOBSB: dupAppend(getSOBSB(str_orBfr, "getDupAppend"), s_toDuplicate, i_dupCount) **/ public final SOBStringBuffer getDupAppend(StringOrBuffer str_orBfr, String s_toDuplicate, int i_dupCount) { SOBStringBuffer ssb = getSOBSB(str_orBfr, "getDupAppend"); dupAppend(ssb, s_toDuplicate, i_dupCount); return ssb; } /**

Get the array index of the first non-white-space character.

@return getIdxOf1stCharNIA(str_orBfr, UtilChar.getAOCInvisible(), bFALSE_IN_PRODUCTION) **/ public final int getIdxOf1stNonWS(StringOrBuffer str_orBfr) { return getIdxOf1stCharNIA(str_orBfr, UtilChar.getAOCInvisible(), bFALSE_IN_PRODUCTION); } /**

Get the array index of the last non-white-space character.

@return getIdxOfLastCharNIA(str_orBfr, UtilChar.getAOCInvisible(), bFALSE_IN_PRODUCTION) **/ public final int getIdxOfLastNonWS(StringOrBuffer str_orBfr) { return getIdxOfLastCharNIA(str_orBfr, UtilChar.getAOCInvisible(), bFALSE_IN_PRODUCTION); } /**

Get the array index of the first character that is not a member of the array.

@return getIdxOf1stCharNIA(str_orBfr, a_char, bFALSE_IN_PRODUCTION) **/ public final int getIdxOf1stCharNIA(StringOrBuffer str_orBfr, char[] a_char) { return getIdxOf1stCharNIA(str_orBfr, a_char, bFALSE_IN_PRODUCTION); } /**

Get the array index of the first character that is not a member of the array.

@return getIdxOf1stCharNIA(str_orBfr, a_char, 0, str_orBfr.length(), b_validateAOC) **/ public final int getIdxOf1stCharNIA(StringOrBuffer str_orBfr, char[] a_char, boolean b_validateAOC) { try { return getIdxOf1stCharNIA(str_orBfr, a_char, 0, str_orBfr.length(), b_validateAOC); } catch(NullPointerException npx) { throwAX("getIdxOf1stCharNIA: str_orBfr is null."); } //Never reached. Required for compile. return -1; } /**

Get the array index of the first character that is not a member of the array.

@return getIdxOf1stCharNIA(str_orBfr, a_char, i_idxStart, i_idxFirstfterEnd, bFALSE_IN_PRODUCTION) **/ public final int getIdxOf1stCharNIA(StringOrBuffer str_orBfr, char[] a_char, int i_idxStart, int i_idxFirstfterEnd) { return getIdxOf1stCharNIA(str_orBfr, a_char, i_idxStart, i_idxFirstfterEnd, bFALSE_IN_PRODUCTION); } /**

Get the array index of the first character that does not exist in the array.

See getIdxOfLastCharNIA for parameter documentation. The only difference between this and that is the side/direction searched.

**/ public final int getIdxOf1stCharNIA(StringOrBuffer str_orBfr, char[] a_char, int i_idxStart, int i_idxFirstfterEnd, boolean b_validateAOC) { return getArrIdxOfCharNIA(str_orBfr, "1", a_char, i_idxStart, i_idxFirstfterEnd, b_validateAOC); } /**

Get the array index of the last character that is not a member of the array.

@return getIdxOfLastCharNIA(str_orBfr, a_char, bFALSE_IN_PRODUCTION) **/ public final int getIdxOfLastCharNIA(StringOrBuffer str_orBfr, char[] a_char) { return getIdxOfLastCharNIA(str_orBfr, a_char, bFALSE_IN_PRODUCTION); } /**

Get the array index of the last character that is not a member of the array.

@return getIdxOfLastCharNIA(str_orBfr, a_char, 0, length(), b_validateAOC) **/ public final int getIdxOfLastCharNIA(StringOrBuffer str_orBfr, char[] a_char, boolean b_validateAOC) { try { return getIdxOfLastCharNIA(str_orBfr, a_char, 0, str_orBfr.length(), b_validateAOC); } catch(NullPointerException npx) { throwAX("getIdxOf1stCharNIA: str_orBfr is null."); } //Never reached. Required for compile. return -1; } /**

Get the array index of the last character that is not a member of the array.

@return getIdxOfLastCharNIA(str_orBfr, a_char, i_idxStart, i_idxFirstfterEnd, bFALSE_IN_PRODUCTION) **/ public final int getIdxOfLastCharNIA(StringOrBuffer str_orBfr, char[] a_char, int i_idxStart, int i_idxFirstfterEnd) { return getIdxOfLastCharNIA(str_orBfr, a_char, i_idxStart, i_idxFirstfterEnd, bFALSE_IN_PRODUCTION); } /**

Get the array index of the last character that does not exist in the array.

See getIdxOf1stCharNIA.

@param str_orBfr The StringOrBuffer to analyze. May not be null, or zero characters in length. @param a_char The array of characters........................... Must be non-null, at least one character in length, and each element must be unique and sorted ascending. @param i_idxStart The first/left-most array index (inclusive) at which to start analyzing. Must be between zero, and length, inclusive, and may not be greater than i_idxFirstfterEnd. @param i_idxFirstfterEnd The last/right-most array index (exclusive) at which to stop analyzing. Must be between zero, and length(), inclusive, and may not be less than or equal to i_idxStart. @param b_validateAOC If true, then it is verified that a_char conforms to its documented restrictions (an AssertException is thrown when any are violated). If false, it is assumed that it does conform. Set this to false only when you are positive a_char is valid, otherwise you will get unpredictable results/errors. Beeeeeeeee careful (reference to Disney's Alladin). @return The array index at which the last character-not-in-a_char exists, or -1, if (1) only characters in a_char exists, or (2) length() equals zero. **/ public final int getIdxOfLastCharNIA(StringOrBuffer str_orBfr, char[] a_char, int i_idxStart, int i_idxFirstfterEnd, boolean b_validateAOC) { return getArrIdxOfCharNIA(str_orBfr, "La", a_char, i_idxStart, i_idxFirstfterEnd, b_validateAOC); } /**

Get a copy of the StringOrBuffer (as an SOBStringBuffer), where the contents' invisible characters are made visible.

@return The contents of getSOBSB: makeVisible(getSOBSB(str_orBfr, "getVisible")) **/ public final StringOrBuffer getVisible(StringOrBuffer str_orBfr) { SOBStringBuffer ssb = getSOBSB(str_orBfr, "getVisible"); makeVisible(ssb); return ssb; } /**

Translate the contents of the StringOrBuffer, so all invisible characters are made visible.

Specifically each '\\n', '\\f', '\\r' and '\\t' is translated to "\\\\n", "\\\\f", "\\\\r", "\\\\t", respectively.

@param str_orBfr The StringOrBuffer to translate. **/ public final void makeVisible(StringOrBuffer str_orBfr) { try { for(int i = 0; i < str_orBfr.length(); i++) { char c = str_orBfr.charAt(i); if(c == '\n') { str_orBfr.deleteCharAt(i); str_orBfr.insert(i, "\\n"); } if(c == '\t') { str_orBfr.deleteCharAt(i); str_orBfr.insert(i, "\\t"); } if(c == '\f') { str_orBfr.deleteCharAt(i); str_orBfr.insert(i, "\\f"); } if(c == '\r') { str_orBfr.deleteCharAt(i); str_orBfr.insert(i, "\\r"); } } } catch(NullPointerException npx) { throwAX("makeVisible: str_orBfr is null."); } } /**

Does the string contain only letters, digits and underscores?

@return isLegal(str_orBfr, true, true, new char[] {'_'}) **/ public boolean isLetterDigitUnderscore(StringOrBuffer str_orBfr) { throwAXIfBadSOB(str_orBfr, "str_orBfr", "isLetterDigitUnderscore"); return isLegal(str_orBfr, true, true, new char[] {'_'}); } /**

Does the string contain only letters and (other provided) legal characters?

@return hasLettersOrInAOC(str_orBfr, b_digitsOkOpt, ac_legal, bFALSE_IN_PRODUCTION) **/ public boolean hasLettersOrInAOC(StringOrBuffer str_orBfr, boolean b_digitsOkOpt, char[] ac_legal) { return hasLettersOrInAOC(str_orBfr, b_digitsOkOpt, ac_legal, bFALSE_IN_PRODUCTION); } /**

Does the string contain only letters and (other provided) legal characters?

@return isLegal(str_orBfr, true, b_digitsOkOpt, ac_legal, b_validateAOC) **/ public boolean hasLettersOrInAOC(StringOrBuffer str_orBfr, boolean b_digitsOkOpt, char[] ac_legal, boolean b_validateAOC) { return isLegal(str_orBfr, true, b_digitsOkOpt, ac_legal, b_validateAOC); } /**

Does the string contain only digits and (other provided) legal characters?

@return hasDigitsOrInAOC(str_orBfr, b_lettersOkOpt, ac_legal, bFALSE_IN_PRODUCTION) **/ public boolean hasDigitsOrInAOC(StringOrBuffer str_orBfr, boolean b_lettersOkOpt, char[] ac_legal) { return hasDigitsOrInAOC(str_orBfr, b_lettersOkOpt, ac_legal, bFALSE_IN_PRODUCTION); } /**

Does the string contain only digits and (other provided) legal characters?

@return isLegal(str_orBfr, b_lettersOkOpt, true, ac_legal, b_validateAOC) **/ public boolean hasDigitsOrInAOC(StringOrBuffer str_orBfr, boolean b_lettersOkOpt, char[] ac_legal, boolean b_validateAOC) { return isLegal(str_orBfr, b_lettersOkOpt, true, ac_legal, b_validateAOC); } /**

Does the string contain only letters, digits and (other provided) legal characters?

@return hasLDOrInAOC(str_orBfr, ac_legal, bFALSE_IN_PRODUCTION) **/ public boolean hasLDOrInAOC(StringOrBuffer str_orBfr, char[] ac_legal) { return hasLDOrInAOC(str_orBfr, ac_legal, bFALSE_IN_PRODUCTION); } /**

Does the string contain only letters, digits and (other provided) legal characters?

@return hasLDOrInAOC(str_orBfr, true, true, ac_legal, b_validateAOC) **/ public boolean hasLDOrInAOC(StringOrBuffer str_orBfr, char[] ac_legal, boolean b_validateAOC) { return isLegal(str_orBfr, true, true, ac_legal, b_validateAOC); } /**

Does the string contain only legal characters?

@return hasLegalChars(str_orBfr, ac_legal, bFALSE_IN_PRODUCTION) **/ public boolean hasLegalChars(StringOrBuffer str_orBfr, char[] ac_legal) { return hasLegalChars(str_orBfr, ac_legal, bFALSE_IN_PRODUCTION); } /**

Does the string contain only legal characters?

@return isLegal(str_orBfr, false, false, ac_legal, b_validateAOC) **/ public boolean hasLegalChars(StringOrBuffer str_orBfr, char[] ac_legal, boolean b_validateAOC) { return isLegal(str_orBfr, false, false, ac_legal, b_validateAOC); } /**

Does the string contain only legal characters?

@return isLegal(str_orBfr, b_lettersOkOpt, b_digitsOkOpt, ac_legal, bFALSE_IN_PRODUCTION) **/ public boolean isLegal(StringOrBuffer str_orBfr, boolean b_lettersOkOpt, boolean b_digitsOkOpt, char[] ac_legal) { return isLegal(str_orBfr, b_lettersOkOpt, b_digitsOkOpt, ac_legal, bFALSE_IN_PRODUCTION); } /**

Does the string contain only legal characters?

@return true If every character causes UtilChar.isLegal(c, b_lettersOkOpt, b_digitsOkOpt, ac_legal, b_validateAOC) to return true. b_validateAOC is only passed once. On the second and subsequent times, this parameter is set to false.
false If any character is not considered legal. **/ public boolean isLegal(StringOrBuffer str_orBfr, boolean b_lettersOkOpt, boolean b_digitsOkOpt, char[] ac_legal, boolean b_validateAOC) { for(int i = 0; i < str_orBfr.length(); i++) { char c = str_orBfr.charAt(i); if(!uChar.isLegal(c, b_lettersOkOpt, b_digitsOkOpt, ac_legal, b_validateAOC)) { return false; } b_validateAOC = false; } //No character is illegal. return true; } /**

Does the string not contain any letters or (other provided) illegal characters?

@return isNotLettersOrInAOC(str_orBfr, b_digitsBadOpt, ac_legal, bFALSE_IN_PRODUCTION) **/ public boolean isNotLettersOrInAOC(StringOrBuffer str_orBfr, boolean b_digitsBadOpt, char[] ac_legal) { return isNotLettersOrInAOC(str_orBfr, b_digitsBadOpt, ac_legal, bFALSE_IN_PRODUCTION); } /**

Does the string not contain any letters or (other provided) illegal characters?

@return isNotIllegal(str_orBfr, true, b_digitsBadOpt, ac_legal, b_validateAOC) **/ public boolean isNotLettersOrInAOC(StringOrBuffer str_orBfr, boolean b_digitsBadOpt, char[] ac_legal, boolean b_validateAOC) { return isNotIllegal(str_orBfr, true, b_digitsBadOpt, ac_legal, b_validateAOC); } /**

Does the string not contain any digits or (other provided) illegal characters?

@return isNotDigitsOrInAOC(str_orBfr, b_digitsBadOpt, ac_legal, bFALSE_IN_PRODUCTION) **/ public boolean isNotDigitsOrInAOC(StringOrBuffer str_orBfr, boolean b_lettersBadOpt, char[] ac_legal) { return isNotDigitsOrInAOC(str_orBfr, b_lettersBadOpt, ac_legal, bFALSE_IN_PRODUCTION); } /**

Does the string not contain any digits or (other provided) illegal characters?

@return isNotIllegal(str_orBfr, b_lettersBadOpt, true, ac_legal, b_validateAOC) **/ public boolean isNotDigitsOrInAOC(StringOrBuffer str_orBfr, boolean b_lettersBadOpt, char[] ac_legal, boolean b_validateAOC) { return isNotIllegal(str_orBfr, b_lettersBadOpt, true, ac_legal, b_validateAOC); } /**

Does the string not contain any letters, digits or (other provided) illegal characters?

@return isNotLDOrInAOC(str_orBfr, ac_legal, bFALSE_IN_PRODUCTION) **/ public boolean isNotLDOrInAOC(StringOrBuffer str_orBfr, char[] ac_legal) { return isNotLDOrInAOC(str_orBfr, ac_legal, bFALSE_IN_PRODUCTION); } /**

Does the string not contain any letters, digits or (other provided) illegal characters?

@return isNotIllegal(str_orBfr, true, true, ac_legal, b_validateAOC) **/ public boolean isNotLDOrInAOC(StringOrBuffer str_orBfr, char[] ac_legal, boolean b_validateAOC) { return isNotIllegal(str_orBfr, true, true, ac_legal, b_validateAOC); } /**

Does the string not contain any illegal characters?

@return hasNoIllegalChars(str_orBfr, ac_illegal, bFALSE_IN_PRODUCTION) **/ public boolean hasNoIllegalChars(StringOrBuffer str_orBfr, char[] ac_illegal) { return hasNoIllegalChars(str_orBfr, ac_illegal, bFALSE_IN_PRODUCTION); } /**

Does the string not contain any illegal characters?

@return isNotIllegal(str_orBfr, false, false, ac_illegal, b_validateAOC) **/ public boolean hasNoIllegalChars(StringOrBuffer str_orBfr, char[] ac_illegal, boolean b_validateAOC) { return isLegal(str_orBfr, false, false, ac_illegal, b_validateAOC); } /**

Does the string not contain any illegal characters?

@return isNotIllegal(str_orBfr, b_lettersBadOpt, b_digitsBadOpt, ac_illegal, bFALSE_IN_PRODUCTION) **/ public boolean isNotIllegal(StringOrBuffer str_orBfr, boolean b_lettersBadOpt, boolean b_digitsBadOpt, char[] ac_illegal) { return isNotIllegal(str_orBfr, b_lettersBadOpt, b_digitsBadOpt, ac_illegal, bFALSE_IN_PRODUCTION); } /**

Does the string not contain any illegal characters?

@return true If every character causes UtilChar.isNotIllegal(c, b_lettersBadOpt, b_digitsBadOpt, ac_illegal, b_validateAOC) to return true (in other words: If every character is not illegal/is legal). b_validateAOC is only passed once. On the second and subsequent times, this parameter is set to false.
false If UtilChar.isNotIllegal returns false for any character. **/ public boolean isNotIllegal(StringOrBuffer str_orBfr, boolean b_lettersBadOpt, boolean b_digitsBadOpt, char[] ac_illegal, boolean b_validateAOC) { for(int i = 0; i < str_orBfr.length(); i++) { char c = str_orBfr.charAt(i); if(!uChar.isNotIllegal(c, b_lettersBadOpt, b_digitsBadOpt, ac_illegal, b_validateAOC)) { //It's not *not* illegal. Meaning it contains an //illegal character. return false; } b_validateAOC = false; } //No character is illegal. return true; } /**

Return a copy of the provided StringOrBuffer (as an SOBStringBuffer), in which all occurances are replaced.

@return The contents of getSOBSB: replaceAll(getSOBSB(sob_searchIn, "getReplaceAll"), s_searchFor, s_replaceWith) **/ public final SOBStringBuffer getReplaceAll(StringOrBuffer sob_searchIn, String s_searchFor, String s_replaceWith) { SOBStringBuffer ssb = getSOBSB(sob_searchIn, "getReplaceAll"); replaceAll(ssb, s_searchFor, s_replaceWith); return ssb; } /**

Replace all occurances. This function returns an int, representing the number of replacements made.

Note

Say the contents of sob_searchIn equals "aaaaa", s_searchFor equals "aa" and s_replaceWith equals "a". The resulting contents of sob_searchIn will be "aaa". In sequence

  1. "aaaaa" is what we're starting with.
  2. Elements zero and one are replaced with a single "a", resulting in "aaaa".
  3. The next "aa" is found at element one, not zero. After replacing elements one and two, we're left with "aaa"
  4. We resume the search at array index two. There are no more occurances of "aa" found at that point, so were done.
  5. This function returns two, reflecting the number of replacements.

Why this behavior? In order to prevent infinite loops. If the search were to resume at the same index (after a replacement), then replacing "a" with "aa" (duplicating, instead of removing duplicates) would never move beyond the index of the first instance of "a". It would just infinitely replace that first "a" with "aa", eventually causing an OutOfMemoryError.

The moral of the story: Run this multiple times in order to replace a superset with it's subset. Say "sLINE_SEP + sLINE_SEP" with "sLINE_SEP" (to eliminate all empty lines). Just keep replacing until this function returns zero.

@param sob_searchIn The string to search through and (potentially) do replacements in. May not be null. @param s_searchFor The string to search for, in sob_searchIn. May not be null or zero characters in length. @param s_replaceWith The string to replace all occurances of s_searchFor with. May not be null or equal to s_searchFor @return The number of replacements made. **/ public final int replaceAll(StringOrBuffer sob_searchIn, String s_searchFor, String s_replaceWith) { throwAXIfBadStr(s_searchFor, "s_searchFor", "replaceAll"); throwAXIfNull(s_replaceWith, "s_replaceWith", "replaceAll"); if(s_replaceWith != null && s_searchFor.equals(s_replaceWith)) { throwAX("replaceAll: s_replaceWith ('" + s_replaceWith + "') is not null, and equal to s_searchFor."); } int iReplacementCount = 0; int iWhat = 0; while(iWhat != -1 && iWhat <= sob_searchIn.length()) { try { iWhat = sob_searchIn.indexOf(s_searchFor, iWhat); } catch(NullPointerException npx) { throwAX("replaceAll: sob_searchIn is null."); } if(iWhat != -1) { iReplacementCount++; sob_searchIn.delete(iWhat, (iWhat + s_searchFor.length())); sob_searchIn.insert(iWhat, s_replaceWith); iWhat += s_replaceWith.length(); } } return iReplacementCount; } /**

Replace all occurances, with multiple passes, until no instances of the search string remain.

@return The SOBStringBuffer after calling replaceUntil((new SOBStringBuffer(sob_searchIn, sUSOB + "getReplaceUntil")), s_searchFor, s_replaceWith) **/ public final SOBStringBuffer getReplaceUntil(StringOrBuffer sob_searchIn, String s_searchFor, String s_replaceWith) { SOBStringBuffer ssb = getSOBSB(sob_searchIn, sUSOB + "getReplaceUntil"); //We don't care what it returns, this is just to indicate that it *does* return something. i_i iiUNRTRND = replaceUntil(ssb, s_searchFor, s_replaceWith); return ssb; } /**

Replace all occurances, with multiple passes, until no instances of the search string remain.

This repeatedly calls replaceAll(sob_searchIn, s_searchFor, s_replaceWith) until zero is returned. See replaceAll for parameter documentation.

@return An i_i containing exactly two ints: **/ public final i_i replaceUntil(StringOrBuffer sob_searchIn, String s_searchFor, String s_replaceWith) { int iReplaceAlls = 0; int iReplacements = 1; int iTotalReplaced = 0; while(iReplacements != 0) { iReplacements = replaceAll(sob_searchIn, s_searchFor, s_replaceWith); iTotalReplaced += iReplacements; iReplaceAlls++; } return new i_i(iTotalReplaced, iReplaceAlls); } /**

Create an SOBString from the StringOrBuffer.

@return getSOBS(str_orBfr, "str_orBfr", s_callingFunc) **/ public final SOBString getSOBS(StringOrBuffer str_orBfr, String s_callingFunc) { return getSOBS(str_orBfr, "str_orBfr", s_callingFunc); } /**

Create an SOBString from the StringOrBuffer.

@param str_orBfr The StringOrBuffer to create an SOBString from. May not be null. @param s_sobDescription The descriptive name of str_orBfr, for potential error messages. @param s_callingFunc The function from which the potential error message should appear as if it is coming from. @return (new SOBString(str_orBfr.toString())) **/ public final SOBString getSOBS(StringOrBuffer str_orBfr, String s_description, String s_callingFunc) { try { return (new SOBString(str_orBfr.toString())); } catch(NullPointerException npx) { throwAX(s_callingFunc + ": " + s_description + " is null."); } //Never reached. Required for compile. return null; } /**

Create an SOBStringBuffer from the StringOrBuffer.

@return getSOBSB(str_orBfr, "str_orBfr", s_callingFunc) **/ public final SOBStringBuffer getSOBSB(StringOrBuffer str_orBfr, String s_callingFunc) { return getSOBSB(str_orBfr, "str_orBfr", s_callingFunc); } /**

Create an SOBString from the StringOrBuffer.

@param str_orBfr The StringOrBuffer to create an SOBStringBuffer from. May not be null. @param s_sobDescription The descriptive name of str_orBfr, for potential error messages. @param s_callingFunc The function from which the potential error message should appear as if it is coming from. @return (new SOBStringBuffer(str_orBfr.toString())) **/ public final SOBStringBuffer getSOBSB(StringOrBuffer str_orBfr, String s_description, String s_callingFunc) { try { return new SOBStringBuffer(str_orBfr.toString()); } catch(NullPointerException npx) { throwAX(s_callingFunc + ": " + s_description + " is null."); } //Never reached. Required for compile. return null; } /**

If the StringOrBuffer is null or empty (the string contained within is zero characters in length), then die. Otherwise do nothing.

@param str_orBfr The StringOrBuffer to analyze for null-ness and emptiness. @param s_sobDescription The descriptive name of str_orBfr, for potential error messages. @param s_callingFunc The function from which a potential error message should appear as if it is coming from. **/ public final void throwAXIfBadSOB(StringOrBuffer str_orBfr, String s_sobDescription, String s_callingFunc) { try { if(str_orBfr.isEmpty()) { throwAX(s_callingFunc + ": " + s_sobDescription + ".isEmpty() equals true."); } } catch(NullPointerException npx) { throwAX(s_callingFunc + ": " + s_sobDescription + " is null."); } } private int getArrIdxOfCharNIA(StringOrBuffer str_orBfr, String s_1OrLa, char[] a_char, int i_idxStart, int i_idxFirstfterEnd, boolean b_validateAOC) { uChar.crashIfAOCNotUnqAscOrd("xbn.string.StringOrBuffer.getArrIdxOfCharNIA", a_char, "a_char", b_validateAOC); if(i_idxStart > i_idxFirstfterEnd) { throwAX("getIdxOf" + s_1OrLa + "stCharNIA: i_idxStart (" + i_idxStart + ") is greater than i_idxFirstfterEnd (" + i_idxFirstfterEnd + ")."); } try { if(s_1OrLa.length() == 1) { for(int i = i_idxStart; i < i_idxFirstfterEnd; i++) { char c = str_orBfr.charAt(i); if(!uChar.isIn(c, a_char, false)) { return i; } } } else { for(int i = (i_idxFirstfterEnd - 1); i >= i_idxStart; i--) { char c = str_orBfr.charAt(i); if(!uChar.isIn(c, a_char, false)) { return i; } } } } catch(NullPointerException npx) { throwAX("getIdxOf" + s_1OrLa + "stCharNIA: str_orBfr is null."); } catch(IndexOutOfBoundsException ioobx) { throwAX("getIdxOf" + s_1OrLa + "stCharNIA: i_idxStart (" + i_idxStart + ") and i_idxFirstfterEnd (" + i_idxFirstfterEnd + ") are invalid. str_orBfr.length()=" + str_orBfr.length() + "."); } return -1; } private String getLmntName(PASStringOrBuffer pas_sob, String[] as_names) { return getLmntName(true, pas_sob, as_names); } private String getLmntName(boolean b_firstSecond, PASStringOrBuffer pas_sob, String[] as_names) { int iIdx = pas_sob.getPAViolation().getIdxFirst(); if(!b_firstSecond) { iIdx = pas_sob.getPAViolation().getIdxSecond(); } if(as_names == null) { return "a_strOrBfr[" + iIdx + "]"; } else { String s = as_names[iIdx]; if(s == null) { return "[---gci_config.getAOSNames()[" + iIdx + "] IS NULL---]"; } else if(s.length() < 1) { return "[---gci_config.getAOSNames()[" + iIdx + "] IS ZERO CHARACTERS IN LENGTH---]"; } return s; } } private int idxLastIdxOfWord(StringOrBuffer str_orBfr, String s_searchWord, int i_idxLeft, int i_idxAfterRight, boolean b_bounded, boolean b_callToIdxOrLastIdx, String s_callingFunc) { throwAXIfBadStr(s_searchWord, "s_searchWord", s_callingFunc); if(!isLetterDigitUnderscore(new SOBString(s_searchWord))) { throwAX(s_callingFunc + ": s_searchWord ('" + s_searchWord + "') must contain only letters, digits and underscores."); } //If this is a call to indexOfWord, then this is used. int iIdxLeftMoving = i_idxLeft; //If this is a call to lastIndexOfWord, then *this* is //used. int iIARMoving = i_idxAfterRight; while(true) { int iIdx = -1; try { if(b_callToIdxOrLastIdx) { iIdx = str_orBfr.indexOf(s_searchWord, iIdxLeftMoving, i_idxAfterRight, b_bounded); } else { iIdx = str_orBfr.lastIndexOf(s_searchWord, i_idxLeft, iIARMoving, b_bounded); } } catch(NullPointerException npx) { throwAX(s_callingFunc + ": str_orBfr is null."); } if(iIdx == -1) { //Not found at all. return -1; } //Found. Is it a word? final char[] acUnderscore = new char[] {'_'}; //If the first character in the found search word is //the very first character in the search bounds, then //this is definitely the start of a word. If there are //characters in the string before i_idxLeft, //charAt(i_idxLeft - 1) may actually be a letter, //digit, or number. // //(It's a decision to assume that i_idxLeft *is* the //beginning of a word.) boolean bWordStart = (iIdx == i_idxLeft); if(!bWordStart) { //The string is found at an index other than i_idxLeft. if(!uChar.isLDOrIn(str_orBfr.charAt(iIdx - 1), acUnderscore)) { //The immediately preceding character is *not* a //letter/digit/underscore. Therefore this is //(truly) the start of a word. bWordStart = true; } else { //The character immediately preceding the search //string is truly a letter digit or underscore. //Therefore s_searchWord is actually part of a //larger word. if(b_callToIdxOrLastIdx) { //(This is a call to indexOf and...) //For the next search, increate the left index to //*two* characters after the currently found //search word (length() + 1). Why two? Because //we know that the last character in the just //found word is a letter, digit or underscore. //Therefore, even if the next occurance were //found at the very next character, we already //know it's not the beginning of a word (because //the last character in this just-found word) //immediately precedes it. iIdxLeftMoving += s_searchWord.length() + 1; if(iIdxLeftMoving > i_idxAfterRight) { //Nothing left to search. return -1; } } else { //(This is a call to lastIndexOf and...) iIARMoving = getNewIARMoving(b_bounded, iIdx, s_searchWord.length()); if(iIARMoving <= i_idxLeft) { //Nothing left to search. return -1; } } //More to search. continue; } } //This *is* the start of a word. boolean bWordEnd = false; //The index immediately following the search word. int iIdxAftrSrch = (iIdx + s_searchWord.length()); if(b_bounded) { //When bounded, the end of the search string is //definitely contained in the bounds. In this case, //it is a decision to assume that //(i_idxAfterRight - 1) is the end of a word. bWordEnd = (iIdxAftrSrch == i_idxAfterRight); } else { //It's not bounded. Only the very last character in //the entire string is (definitely) the end of a //word. if(iIdxAftrSrch == str_orBfr.length()) { //The last character in the search string is //truly the last character in the string. bWordEnd = true; } } if(!bWordEnd) { //This is not the end of the word...so far. // //We do know that there *is* a character immediately //following the found string. Is it a word //delimiter? if(!uChar.isLDOrIn(str_orBfr.charAt(iIdxAftrSrch), acUnderscore)) { //The immediately following character is *not* a //letter/digit/underscore. Therefore this is //the end of a word. It is a word delimiter. bWordEnd = true; } else { //The character immediately following the search //string *is* a letter digit or underscore. //Therefore it is not a word delimiter, and //s_searchWord is actually part of a larger word. if(b_callToIdxOrLastIdx) { //(This is a call to indexOf and...) //More to search. iIdxLeftMoving += iIdxAftrSrch + 1; if(iIdxLeftMoving > i_idxAfterRight) { //Nothing left to search. return -1; } } else { //(This is a call to lastIndexOf and...) iIARMoving = getNewIARMoving(b_bounded, iIdx, s_searchWord.length()); if(iIARMoving < i_idxLeft) { //Nothing left to search. return -1; } //More to search. } //This is definitely not a word, and there *is* //more to search. continue; } //END: Not a word-end. } //This may or may not be the end of a word. if(bWordStart && bWordEnd) { return iIdx; } //ELSE: More to search. } } private int getNewIARMoving(boolean b_bounded, int i_idx, int i_searchWordLength) { if(b_bounded) { //The character before the just-found //string is definitely not the end of a //word (because the first character in the //just-found string immediately follows //it!). // //So the end bound must be the character //one before that. return i_idx - 1; } else { //Not a bounded search. Close in the //after-right bound so that we don't search //any of the string redundantly or //unecessarily. return (i_idx - (i_searchWordLength + 1)); } } }