/* 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.APChar; import xbn.array.primitive.PACChar; import xbn.array.primitive.PARCStrict; import xbn.array.primitive.PAROrderDir; import xbn.placeholder.i_i; import java.util.Arrays; /**

Trim characters off the ends of a string.

Source code:  TrimChars.java

@version 0.9b @author Jeff Epstein, http://sourceforge.net/projects/xbnjava. **/ public class TrimChars extends XBNObject { private final UtilSOB uSOB = new UtilSOB(); private static final String sT = "xbn.string.TrimChars."; private final UtilChar uChar = new UtilChar(); private final UtilString uStr = new UtilString(); private final UtilStringBuffer uSB = new UtilStringBuffer(); private char[] acToTrim = null; private TALConfig talc = null; private boolean bCheckRightForEsc = false; private char cEscape = ' '; private i_i iiTrimData = null; /**

Create a TrimChars with default settings.

Equal to TrimChars(UtilChar.getAOCTabSpace())

**/ public TrimChars() { this(UtilChar.getAOCTabSpace()); } /**

Create a TrimChars.

Equal to TrimChars(ac_charsToTrim, bFALSE_IN_PRODUCTION)

**/ public TrimChars(char[] ac_charsToTrim) { this(ac_charsToTrim, bFALSE_IN_PRODUCTION); } /**

Create a TrimChars.

Equal to TrimChars(ac_charsToTrim, b_checkRightForEsc, c_escape, bFALSE_IN_PRODUCTION)

**/ public TrimChars(char[] ac_charsToTrim, boolean b_checkRightForEsc, char c_escape) { this(ac_charsToTrim, b_checkRightForEsc, c_escape, bFALSE_IN_PRODUCTION); } /**

Create a TrimChars.

Equal to TrimChars(ac_charsToTrim, true, c_escape)

**/ public TrimChars(char[] ac_charsToTrim, char c_escape) { this(ac_charsToTrim, true, c_escape); } /**

Create a TrimChars.

Equal to TrimChars((UtilChar.getAOCTabSpace(), tal_config)

**/ public TrimChars(TALConfig tal_config) { this(UtilChar.getAOCTabSpace(), tal_config); } /**

Create a TrimChars.

Equal to TrimChars((ac_toTrim, tal_config, bFALSE_IN_PRODUCTION)

**/ public TrimChars(char[] ac_toTrim, TALConfig tal_config) { this(ac_toTrim, tal_config, bFALSE_IN_PRODUCTION); } /**

Create a TrimChars.

Equal to TrimChars(ac_toTrim, (new TALConfig()), b_validateACToTrim)

**/ public TrimChars(char[] ac_toTrim, boolean b_validateACToTrim) { this(ac_toTrim, (new TALConfig()), b_validateACToTrim); } /**

Create a TrimChars.

Equal to TrimChars(ac_toTrim, tal_config, false, ' ', b_validateACToTrim)

**/ public TrimChars(char[] ac_toTrim, TALConfig tal_config, boolean b_validateParams) { this(ac_toTrim, tal_config, false, ' ', b_validateParams); } /**

Create a TrimChars.

Equal to TrimChars(ac_toTrim, tal_config, b_checkRightForEsc, c_escape, bFALSE_IN_PRODUCTION)

**/ public TrimChars(char[] ac_toTrim, TALConfig tal_config, boolean b_checkRightForEsc, char c_escape) { this(ac_toTrim, tal_config, b_checkRightForEsc, c_escape, bFALSE_IN_PRODUCTION); } /**

Create a TrimChars.

Equal to TrimChars(ac_toTrim, (new TALConfig()), b_checkRightForEsc, c_escape, b_validateParams)

**/ public TrimChars(char[] ac_toTrim, boolean b_checkRightForEsc, char c_escape, boolean b_validateParams) { this(ac_toTrim, (new TALConfig()), b_checkRightForEsc, c_escape, b_validateParams); } /**

Create a TrimChars.

@param ac_toTrim The array of characters to trim. May not be null or zero elements in length. Must have all unique values, ordered ascending ('a', 'b', 'c', ...). See getAPCToTrim. @param tal_config The configuration for trimAllLines. May not be null, and tal_config.getLineSeparator may not contain any characters existing in ac_toTrim (or c_escape, if b_checkRightForEsc is true). See getTALConfig @param b_checkRightForEsc If true, then before the right side is trimmed, it is ensured that the character that is about to be eliminated, is not escaped. If it is, trimming stops. When b_trimRight equals false, this must equal false. See doCheckRightForEsc. @param c_escape The escape character, when b_checkRightForEsc is true (this may not equal any member of ac_toTrim). When b_checkRightForEsc equals false, this must equal ' '. See getEscapeChar. @param b_validateParams If true, then all documented parameter restrictions are checked, and an AssertException is thrown when any violation is found. When false, be darn-tooting sure the parameters coform to documented restrictions. **/ public TrimChars(char[] ac_toTrim, TALConfig tal_config, boolean b_checkRightForEsc, char c_escape, boolean b_validateParams) { if(b_validateParams) { PACChar pacc = new PACChar(ac_toTrim, (new PARCStrict(new PAROrderDir(true)))); pacc.crashIfBad(sT + sCNSTR, "ac_toTrim"); try { if(!uStr.hasNoIllegalChars(tal_config.getLineSeparator(), ac_toTrim)) { throwAX("constructor: tal_config.getLineSeparator() ('" + (new UtilString()).getVisible(tal_config.getLineSeparator()) + "') has at least one character that also exists in ac_toTrim: " + (new APChar(acToTrim)).getList("['", "', '", "']")); } } catch(NullPointerException npx) { throwAX("constructor: tal_config is null."); } if(doCheckRightForEsc() && Arrays.binarySearch(ac_toTrim, getEscapeChar()) != -1) { int i = Arrays.binarySearch(ac_toTrim, getEscapeChar()); throwAX("constructor: doCheckRightForEsc() equals true, and getEscapeChar() ('" + getEscapeChar() + "') is equal to ac_toTrim[" + i + "] ('" + ac_toTrim[i] + "')."); } } acToTrim = ac_toTrim; talc = tal_config; bCheckRightForEsc = b_checkRightForEsc; cEscape = c_escape; } /**

Get the array of characters to be trimmed.

@return new APChar(ac_toTrim) Where ac_toTrim is exactly as provided to the constructor. **/ public final APChar getAPCToTrim() { return (new APChar(acToTrim)); } /**

Get the TALConfig, which holds the configuration for trimAllLines. See trimAllLines.

@return tal_config Exactly as provided to the constructor. **/ public final TALConfig getTALConfig() { return talc; } /**

Should only non-escaped characters be trimmed from the right side?

When this equals true, getEscapeChar is used. When this returns false, getEscapeChar is ignored.

@return b_checkRightForEsc Exactly as provided to the constructor. **/ public final boolean doCheckRightForEsc() { return bCheckRightForEsc; } /**

The escape character, when only non-escaped chararcters are trimmed from the right side.

When this character preceds a to-be-trimmed character existing on the right hand side of a string, then it is not trimmed.

See doCheckRightForEsc. If doCheckRightForEsc equals false, this is ignored.

@return c_escape Exactly as provided to the constructor. **/ public final char getEscapeChar() { return cEscape; } /**

Get a copy of the string where characters have been trimmed.

@return get([UtilString].getSOBSB(s_tr, "xbn.string.TrimChars.get")).toString() **/ public final String get(String s_tr) { return get(uStr.getSOBSB(s_tr, sT + "get")).toString(); } /**

Get a copy of the string where characters have been trimmed.

@return get([UtilString].getSOBSB(s_tr, "xbn.string.TrimChars.get"), i_idxLeft, i_idxAfterRight).toString() **/ public final String get(String s_tr, int i_idxLeft, int i_idxAfterRight) { return get(uStr.getSOBSB(s_tr, sT + "get"), i_idxLeft, i_idxAfterRight).toString(); } /**

Get a copy of the StringBuffer where characters have been trimmed.

@return get([UtilStringBuffer].getSOBSB(str_buffer, "xbn.string.TrimChars.get")).getStringBuffer() **/ public final StringBuffer get(StringBuffer str_buffer) { return get(uSB.getSOBSB(str_buffer, sT + "get")).getStringBuffer(); } /**

Get a copy of the StringBuffer where characters have been trimmed.

@return get([UtilStringBuffer].getSOBSB(str_buffer, "xbn.string.TrimChars.get"), i_idxLeft, i_idxAfterRight).getStringBuffer() **/ public final StringBuffer get(StringBuffer str_buffer, int i_idxLeft, int i_idxAfterRight) { return get(uSB.getSOBSB(str_buffer, sT + "get"), i_idxLeft, i_idxAfterRight).getStringBuffer(); } /**

Get a copy of the StringOrBuffer (as an SOBStringBuffer) where characters have been trimmed.

@return The contents of getSOBSB: trim([UtilSOB].getSOBSB(str_orBfr, "xbn.string.TrimChars.get")) **/ public final SOBStringBuffer get(StringOrBuffer str_orBfr) { SOBStringBuffer ssb = uSOB.getSOBSB(str_orBfr, sT + "get"); trim(ssb); return ssb; } /**

Get a copy of the StringOrBuffer (as an SOBStringBuffer) where characters have been trimmed.

@return The contents of getSOBSB: trim([UtilSOB].getSOBSB(str_orBfr, "xbn.string.TrimChars.get"), i_idxLeft, i_idxAfterRight) **/ public final SOBStringBuffer get(StringOrBuffer str_orBfr, int i_idxLeft, int i_idxAfterRight) { SOBStringBuffer ssb = uSOB.getSOBSB(str_orBfr, sT + "get"); trim(ssb, i_idxLeft, i_idxAfterRight); return ssb; } /**

Trim characters off the ends of the StringBuffer.

@return trim([UtilStringBuffer].getSOBSB(str_buffer, "xbn.string.TrimChars.trim")) **/ public final i_i trim(StringBuffer str_buffer) { return trim(uSB.getSOBSB(str_buffer, sT + "trim")); } /**

Trim characters off the ends of the StringBuffer.

@return trim([UtilStringBuffer].getSOBSB(str_buffer, "xbn.string.TrimChars.trim"), i_idxLeft, i_idxAfterRight) **/ public final i_i trim(StringBuffer str_buffer, int i_idxLeft, int i_idxAfterRight) { return trim(uSB.getSOBSB(str_buffer, sT + "trim"), i_idxLeft, i_idxAfterRight); } /**

Trim characters off the ends of the StringOrBuffer.

@return trim(str_orBfr, 0, str_orBfr.length()) **/ public final i_i trim(StringOrBuffer str_orBfr) { try { return trim(str_orBfr, 0, str_orBfr.length()); } catch(NullPointerException npx) { throwAX("trim: str_orBfr is null."); } //Never reached. Required for compile. return null; } /**

Trim characters off the ends of the StringOrBuffer.

@param str_orBfr The StringOrBuffer to trim. May not be null. @param i_idxLeft The left-most index in str_orBfr to start trimming from. If -1, then do not trim characters from the left side. Otherwise, must be a valid string index for str_orBfr, may not be greater than i_idxAfterRight (assuming i_idxAfterRight is not equal to -1). @param i_idxAfterRight The string index after the right-most index in str_orBfr to start trimming from. If -1, then do not trim characters from the right side. Otherwise, must be a valid string index for str_orBfr, and may not be less than i_idxLeft (assuming i_idxLeft is not equal to -1). @return null If both i_idxLeft and i_idxRight are equal to -1.
A i_i where i1 is the number of characters trimmed off the left side (if i_idxLeft equals -1, i1 will equal 0), and i2 is the number of characters trimmed off the right side (if i_idxAfterRight equals -1, i2 will equal 0). **/ public final i_i trim(StringOrBuffer str_orBfr, int i_idxLeft, int i_idxAfterRight) { iiTrimData = null; if(i_idxLeft != -1) { if(i_idxLeft < 0) { throwAX("constructor: i_idxLeft (" + i_idxLeft + ") must equal -1, or be greater than -1."); } if(i_idxAfterRight == -1) { //Nothing to trim. return null; } } else if(i_idxAfterRight != -1) { if(i_idxAfterRight < 0) { throwAX("constructor: i_idxAfterRight (" + i_idxAfterRight + ") must equal -1, or be greater than -1."); } if(i_idxLeft == -1) { //Nothing to trim. return null; } } else { //Both i_idxLeft and i_idxAfterRight are not -1. if(i_idxLeft > i_idxAfterRight) { throwAX("constructor: i_idxLeft (" + i_idxLeft + ") is greater than i_idxAfterRight (" + i_idxAfterRight + ")."); } } //The bounds are legal, as far as how they relate to each //other. They may or may not be legal, given the length //of the provided string. //And there is definitely at least one side that needs to //be trimmed. int iLeftTrimmed = 0; int iRightTrimmed = 0; int i = i_idxLeft; int iAR = i_idxAfterRight; int iOrigLen = -1; try { iOrigLen = str_orBfr.length(); } catch(NullPointerException npx) { throwAX("trim: str_orBfr is null."); } if(i != -1) { //Trim the left side. try { while(i < iAR) { if(uChar.isIn(str_orBfr.charAt(i), acToTrim)) { str_orBfr.deleteCharAt(i); //In the next iteration of this loop, since we //just deleted a character the index-after- //the-right-most one has just been pulled one //to the left (less). iAR--; iLeftTrimmed++; } else { break; } } } catch(IndexOutOfBoundsException ioobx) { throwAX("trim: i_idxLeft (" + i_idxLeft + ") and i_idxAfterRight (" + i_idxAfterRight + ") are illegal. str_orBfr.length()=" + iOrigLen + "."); } } if(iAR != -1) { //Trim the right side. //iAR is the character *after* the right-most to analyze. i = iAR - 1; try { while(i >= i_idxLeft) { if(uChar.isIn(str_orBfr.charAt(i), acToTrim)) { //The right-most character is one of the ones //to be trimmed. if(doCheckRightForEsc() && i > i_idxLeft) { //Don't eliminate it if it is escaped, and //there *is* room for the escape character //to exist. if(str_orBfr.charAt(i - 1) == getEscapeChar()) { //Don't eliminate this, because it is //escaped. break; } } //It needs to be trimmed. str_orBfr.deleteCharAt(i); iRightTrimmed++; //Move back one character. to point to the one //previous to the one just deleted. i--; } else { break; } } } catch(IndexOutOfBoundsException ioobx) { throwAX("trim: i_idxLeft (" + i_idxLeft + ") and i_idxAfterRight (" + i_idxAfterRight + ") are illegal. str_orBfr.length()=" + iOrigLen + "."); } } iiTrimData = new i_i(iLeftTrimmed, iRightTrimmed); return iiTrimData; } /**

Get information about the just-called trim or get. See trim and get.

@return An i_i where i1 is the number of characters eliminated from the left side of the string, and i2 is the number eliminated from the right.
null If trim and get were never called, or threw an exception for any reason. **/ public final i_i getTrimData() { return iiTrimData; } /**

Get a copy of the string where characters have been trimmed from the ends of every line.

@return getAllLines([UtilString].getSOBSB(s_tr, "xbn.string.TrimChars.getAllLines")).toString() **/ public final String getAllLines(String s_tr) { return getAllLines(uStr.getSOBSB(s_tr, sT + "getAllLines")).toString(); } /**

Get a copy of the StringBuffer where characters have been trimmed from the ends of every line.

@return getAllLines([UtilStringBuffer].getSOBSB(str_buffer, "xbn.string.TrimChars.getAllLines")).toString() **/ public final StringBuffer getAllLines(StringBuffer str_buffer) { return getAllLines(uSB.getSOBSB(str_buffer, sT + "getAllLines")).getStringBuffer(); } /**

Get a copy of the StringOrBuffer where characters have been trimmed from the ends of every line.

@return The contents of getSOBSB: trimAllLines([UtilSOB].getSOBSB(str_orBfr, "xbn.string.TrimChars.getAllLines")) **/ public final SOBStringBuffer getAllLines(StringOrBuffer str_orBfr) { SOBStringBuffer ssb = uSOB.getSOBSB(str_orBfr, sT + "getAllLines"); trimAllLines(ssb); return ssb; } /**

Trim characters off the ends of every line in the StringBuffer.

Equal to trimAllLines([UtilStringBuffer].getSOBSB(str_buffer, "xbn.string.TrimChars.trimAllLines"))

**/ public final void trimAllLines(StringBuffer str_buffer) { trimAllLines(uSB.getSOBSB(str_buffer, sT + "trimAllLines")); } /**

TrimChars the characters from the start and end of each line within the StringOrBuffer. The configuration for this function is held by getTALConfig.

@param str_orBfr The StringOrBuffer to trim. May not be null. **/ public final void trimAllLines(StringOrBuffer str_orBfr) { int iStart = 0; int iAfterEnd = 0; try { while(iAfterEnd != -1 && iStart < str_orBfr.length()) { try { iAfterEnd = str_orBfr.indexOf(getTALConfig().getLineSeparator(), iStart); } catch(NullPointerException npx) { throwAXIfNull(str_orBfr, "str_orBfr", "trimAllLines"); throwAXIfNull(getTALConfig(), "getTALConfig() [tal_config, as provided to the constructor]", "trimAllLines"); } if(iAfterEnd == -1) { //This is the last line (because iStart is still //less than sob.length). iAfterEnd = str_orBfr.length(); } int iStart4trim = -1; if(getTALConfig().doTrimLeft()) { iStart4trim = iStart; } int iAfterEnd4trim = -1; if(getTALConfig().doTrimRight()) { iAfterEnd4trim = iAfterEnd; } i_i ss = trim(str_orBfr, iStart4trim, iAfterEnd4trim); //Point to the first character in the next line. //ss.i1 and i2 compensate for the number of //characters deleted in the previous line. iStart = iAfterEnd + getTALConfig().getLineSeparator().length() - ss.i1 - ss.i2; } } catch(NullPointerException npx) { throwAX("trimAllLines: str_orBfr is null."); } /** //I think this may be UN-neccessary. Verify by using ReportDependencies... //For some reason, this is *adding* new lines to the //(very) start and end of the text. str_orBfr.trim(); **/ } }