001package Torello.Java;
002
003import java.util.function.Consumer;
004import java.util.function.Predicate;
005import java.util.Vector;
006
007import Torello.Java.Shell.C;
008import Torello.HTML.Tools.JavaDoc.StaticFunctional;
009import Torello.HTML.Tools.JavaDoc.Excuse;
010
011/**
012 * Similar to class String-Compare, String-Token-Compare also provides an exhaustive suite of
013 * methods that extend the basic Java <CODE>String</CODE> methods <CODE>equals, contains,
014 * startsWith</CODE> and <CODE>endsWith</CODE>, but further allowing a user to specify the 
015 * match-string boundary-characters.
016 * 
017 * <BR /><BR /><EMBED CLASS="external-html" DATA-FILE-ID="STC_STC">
018 */
019@StaticFunctional(Excused={"DEBUG", "DEBUG_LOG"}, Excuses={Excuse.DEBUGGING, Excuse.DEBUGGING})
020public class StrTokCmpr
021{
022    private StrTokCmpr() { }
023
024    /**
025     * Utility field.  You may choose to set this variable to true, and the following
026     * {@code String} commands will print to  an internally stored {@code Consumer<String> DEBUG_LOG}
027     * class that may be set.  This is generally a very minor drain on code-efficiency.  When this
028     * flag is set to <B>FALSE</B>, a short {@code if-statement evaluation} <I>still occurs even
029     * when the flag is false</I> on each occasion that the string-comparison loops identify and
030     * return a match.  This is very minor performance loss, and does provide quite a lot of help
031     * to those trying to identify difficult to notice problems with partial-{@code String}
032     * comparisons.
033     * 
034     * <BR /><BR /><B><SPAN STYLE="color: red;">IMPORTANT:</B></SPAN> In order to use this minor
035     * debugging feature, it is necessary to provide a {@code Consumer<String> DEBUG_LOG} to the
036     * {@code public static } field!  If this field is not set to a valid, {@code non-null}
037     * object-reference, then this class will through a {@code NullPointerException} on its first
038     * attempt to compare strings.  This {@code String}-consumer may do anything it wants with the
039     * debug-{@code String} information.
040     *
041     * <BR /><BR /><B>FORMAT:</B> The output string format is just:
042     * <DIV CLASS="SNIP">{@code
043     * private static void PRNT(String methodName, String srcStr, String token)
044     * { DEBUG_LOG.accept(methodName + "-MATCH[" + srcStr + ", " + token + "] "); }
045     * }</DIV>
046     * <BR />Generally, you would want to use a simple lambda such as:
047     * <DIV CLASS="EXAMPLE">{@code
048     * StrCmpr.DEBUG_LOG = (String logInfoStr) -> System.out.println(logInfoStr);
049     * }</DIV>
050     *
051     * <BR /><BR /><B>FINALLY:</B> If you are logging, please note that any of the methods whose
052     * name ends with the phrase "IgnoreCase" <I>will not contribute (print) to the log.</I>  this
053     * is primarily because these are all <I>single-argument comparisons</I>, and logging would be
054     * of only minor benefit.  The primary benefit of a debug-log is the ability to identify
055     * which/when a particular substring from a list of substrings actually matched.  The methods
056     * whose names contain the two letter acronym "_CI" are all "Case Insensitive" - and they also
057     * do comparisons to multiple-input var-args {@code String} parameters.
058     */
059    public static boolean DEBUG = false;
060
061    /**
062     * This object reference <I><B>cannot be null when DEBUG is TRUE</B></I>.  This
063     * {@code StorageWriter} will receive text-notifications every time the string-comparing loops
064     * identify a match.
065     *
066     * <BR /><BR /><B><SPAN STYLE="color: red;">IMPORTANT:</B></SPAN> No attempt has been made to
067     * ensure that this debugging feature will operate perfectly in a multi-threaded environment.
068     * The two reasons for this are:
069     *
070     * <BR /><BR /><OL CLASS=JDOL>
071     * <LI>The primary purpose of this LOG is for debugging code, not putting details about
072     *     string-match information into an 'on-line' or production environment.
073     * </LI>
074     * <LI>This is a best-efforts string-comparison package that would sacrifice quite a bit of its
075     *     utility if it were expected to maintain multiple instances of this class just to have
076     *     {@code StrCmpr} debug operations work in multiple-threads.  Code readability necessitates
077     *     keeping this a class with only <B><I>static methods.</I></B>
078     * </LI>
079     * <LI>Two threads making calls to this {@code class StrCmpr} might see log-writes that, sadly,
080     *     look like they 'interlaced' (crashed), but even when this occasions, reading the log
081     *     wouldn't be that difficult anyway.
082     * </LI>
083     * </OL>
084     */
085    public static Consumer<String> DEBUG_LOG = null;
086
087    private static void PRNT(String methodName, String srcStr, String token)
088    { DEBUG_LOG.accept(methodName + srcStr + ", " + token + "] "); }
089
090    /**
091     * This performs the internal AND.  It expects a comparison {@code Predicate} in order for the
092     * comparison to work.
093     * @param methodName If printing-debug information is expected, by the DEBUG global-variable,
094     * this {@code String} is used.
095     * @param srcStr This is the same source-string parameter from all the methods in this class.
096     * @param tokens This is the same var-args string array from all the methods in this class.
097     * @param pred This is the comparison {@code Predicate} provided by the methods in this class
098     * that call this method.
099     * @return The AND of these {@code String's}, using the provided {@code Predicate}.
100     * @throws StrCmprException This exception shall throw if there are any invalid
101     * {@code String's} in the compare-string parameter array.
102     * <BR /><BR /><SPAN STYLE="color: red;"><B>IMPORTANT NOTE:</SPAN></B> The conditions that
103     * would cause this exception to throw should remind the reader that <I><B>each and every
104     * method here</I></B> will throw exception 'StrCmprException' if invalid input has been
105     * passed to the "Compare String" Variable-Arguments {@code String...} Parameter.
106     */
107    protected static boolean AND
108        (String methodName, String srcStr, String[] tokens, Predicate<String> pred)
109    {
110        StrCmprException.check(tokens);
111
112        for (String cmp: tokens)
113
114            if (! pred.test(cmp))
115            {
116                if (DEBUG) PRNT(methodName + "-MATCHFAIL", srcStr, cmp);
117                return false;
118            }
119
120        return true;
121    }
122
123    /**
124     * This performs the internal NAND.  It expects a comparison {@code Predicate} in order for the
125     * comparison to work.
126     * @param methodName If printing-debug information is expected, by the DEBUG global-variable,
127     * this {@code String} is used.
128     * @param srcStr This is the same source-string parameter from all the methods in this class.
129     * @param tokens This is the same var-args string array from all the methods in this class.
130     * @param pred This is the comparison {@code Predicate} provided by the methods in this class
131     * that call this method.
132     * @return The NAND of these {@code String's}, using the provided {@code Predicate}.
133     * @throws StrCmprException This exception shall throw if there are any invalid
134     * {@code String's} in the compare-string parameter array.
135     * <BR /><BR /><SPAN STYLE="color: red;"><B>IMPORTANT NOTE:</SPAN></B> The conditions that
136     * would cause this exception to throw should remind the reader that <I><B>each and every
137     * method here</I></B> will throw exception 'StrCmprException' if invalid input has been passed
138     * to the "Compare String" Variable-Arguments {@code String...} Parameter.
139     */
140    protected static boolean NAND
141        (String methodName, String srcStr, String[] tokens, Predicate<String> pred)
142    {
143        StrCmprException.check(tokens); 
144
145        for (String cmp: tokens) 
146
147            if (pred.test(cmp))
148            {
149                if (DEBUG) PRNT(methodName + "-MATCH", srcStr, cmp);
150                return false;
151            }
152
153        return true;
154    }
155
156    /**
157     * This performs the internal OR.  It expects a comparison {@code Predicate} in order for the
158     * comparison to work.
159     * @param methodName If printing-debug information is expected, by the DEBUG global-variable,
160     * this {@code String} is used.
161     * @param srcStr This is the same source-string parameter from all the methods in this class.
162     * @param tokens This is the same var-args string array from all the methods in this class.
163     * @param pred This is the comparison {@code Predicate} provided by the methods in this class
164     * that call this method.
165     * @return The OR of these {@code String's}, using the provided {@code Predicate}.
166     * @throws StrCmprException This exception shall throw if there are any invalid
167     * {@code String's} in the compare-string parameter array.
168     * <BR /><BR /><SPAN STYLE="color: red;"><B>IMPORTANT NOTE:</SPAN></B> The conditions that
169     * would cause this exception to throw should remind the reader that <I><B>each and every
170     * method here</I></B> will throw exception 'StrCmprException' if invalid input has been passed
171     * to the "Compare String" Variable-Arguments {@code String...} Parameter.
172     */
173    protected static boolean OR
174        (String methodName, String srcStr, String[] tokens, Predicate<String> pred)
175    {
176        StrCmprException.check(tokens);
177
178        for (String cmp: tokens)
179
180            if (pred.test(cmp))
181            {
182                if (DEBUG) PRNT(methodName + "-MATCH", srcStr, cmp);
183                return true;
184            }
185
186        return false;
187    }
188
189    /**
190     * This performs the internal XOR.  It expects a comparison {@code Predicate} in order for the
191     * comparison to work.
192     * @param methodName If printing-debug information is expected, by the DEBUG global-variable,
193     * this {@code String} is used.
194     * @param srcStr This is the same source-string parameter from all the methods in this class.
195     * @param tokens This is the same var-args string array from all the methods in this class.
196     * @param pred This is the comparison {@code Predicate} provided by the methods in this class
197     * that call this method.
198     * @return The XOR of these {@code String's}, using the provided {@code Predicate}.
199     * @throws StrCmprException This exception shall throw if there are any invalid
200     * {@code String's} in the compare-string parameter array.
201     * <BR /><BR /><SPAN STYLE="color: red;"><B>IMPORTANT NOTE:</SPAN></B> The conditions that
202     * would cause this exception to throw should remind the reader that <I><B>each and every
203     * method here</I></B> will throw exception 'StrCmprException' if invalid
204     * input has been passed to the "Compare String" Variable-Arguments {@code String...}
205     * Parameter.
206     */
207    protected static boolean XOR
208        (String methodName, String srcStr, String[] tokens, Predicate<String> pred)
209    {
210        StrCmprException.check(tokens); 
211
212        int count=0;
213
214        for (String cmp: tokens)
215
216            if (pred.test(cmp))
217                if (++count > 1)
218                {
219                    if (DEBUG) PRNT(methodName + "-MATCH", srcStr, cmp);
220                    return false;
221                }
222
223        return count == 1;
224    }
225
226
227
228
229
230
231
232
233
234
235
236    // ****************************************************************************************
237    // ****************************************************************************************
238    // ****************************************************************************************
239    // ****************************************************************************************
240    // ****************************************************************************************
241    // ****************************************************************************************
242    // StrCmpr Main Section #1
243    // ****************************************************************************************
244    // ****************************************************************************************
245    // ****************************************************************************************
246    // ****************************************************************************************
247    // ****************************************************************************************
248
249
250    
251    // ****************************************************************************************
252    // CONTAINS
253    // ****************************************************************************************
254
255    /**
256     * <EMBED CLASS=defs DATA-DESC='contains at least one' DATA-CI='is'>
257     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
258     * @param srcStr Any non-null instance of {@code java.lang.String}
259     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
260     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
261     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
262     * @see #CONTAINS(boolean, byte, String, String[])
263     */
264    public static boolean containsOR(String srcStr, String... tokens)
265    { return CONTAINS(false, OR, srcStr, tokens); }
266
267    /**
268     * <EMBED CLASS=defs DATA-DESC='contains every one' DATA-CI='is'>
269     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
270     * @param srcStr Any non-null instance of {@code java.lang.String}
271     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
272     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
273     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
274     * @see #CONTAINS(boolean, byte, String, String[])
275     */
276    public static boolean containsAND(String srcStr, String... tokens)
277    { return CONTAINS(false, AND, srcStr, tokens); }
278
279    /**
280     * <EMBED CLASS=defs DATA-DESC='contains exactly one' DATA-CI='is'>
281     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
282     * @param srcStr Any non-null instance of {@code java.lang.String}
283     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
284     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
285     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
286     * @see #CONTAINS(boolean, byte, String, String[])
287     */
288    public static boolean containsXOR(String srcStr, String... tokens)
289    { return CONTAINS(false, XOR, srcStr, tokens); }
290
291    /**
292     * <EMBED CLASS=defs DATA-DESC='does not contain any' DATA-CI='is'>
293     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
294     * @param srcStr Any non-null instance of {@code java.lang.String}
295     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
296     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
297     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
298     * @see #CONTAINS(boolean, byte, String, String[])
299     */
300    public static boolean containsNAND(String srcStr, String... tokens)
301    { return CONTAINS(false, NAND, srcStr, tokens); }
302
303    /**
304     * <EMBED CLASS=defs DATA-DESC='contains at least one' DATA-CI='is not'>
305     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
306     * @param srcStr Any non-null instance of {@code java.lang.String}
307     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
308     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
309     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
310     * @see #CONTAINS(boolean, byte, String, String[])
311     */
312    public static boolean containsOR_CI(String srcStr, String... tokens)
313    { return CONTAINS(true, OR, srcStr, tokens); }
314
315    /**
316     * <EMBED CLASS=defs DATA-DESC='contains every one' DATA-CI='is not'>
317     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
318     * @param srcStr Any non-null instance of {@code java.lang.String}
319     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
320     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
321     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
322     * @see #CONTAINS(boolean, byte, String, String[])
323     */
324    public static boolean containsAND_CI(String srcStr, String... tokens)
325    { return CONTAINS(true, AND, srcStr, tokens); }
326
327    /**
328     * <EMBED CLASS=defs DATA-DESC='contains exactly one' DATA-CI='is not'>
329     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
330     * @param srcStr Any non-null instance of {@code java.lang.String}
331     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
332     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
333     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
334     * @see #CONTAINS(boolean, byte, String, String[])
335     */
336    public static boolean containsXOR_CI(String srcStr, String... tokens)
337    { return CONTAINS(true, XOR, srcStr, tokens); }
338
339    /**
340     * <EMBED CLASS=defs DATA-DESC='does not contain any' DATA-CI='is not'>
341     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
342     * @param srcStr Any non-null instance of {@code java.lang.String}
343     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
344     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
345     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
346     * @see #CONTAINS(boolean, byte, String, String[])
347     */
348    public static boolean containsNAND_CI(String srcStr, String... tokens)
349    { return CONTAINS(true, NAND, srcStr, tokens); }
350
351    // ****************************************************************************************
352    // STARTS-WITH, ENDS-WITH
353    // ****************************************************************************************
354
355    /**
356     * <EMBED CLASS=defs DATA-DESC='ends with exactly one' DATA-CI='is'>
357     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
358     * @param srcStr Any non-null instance of {@code java.lang.String}
359     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
360     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
361     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
362     * @see #XOR(String, String, String[], Predicate)
363     * @see #endsWith(String, LV, String)
364     */
365    public static boolean endsWithXOR(String srcStr, String... tokens)
366    { return XOR("endsWithXOR", srcStr, tokens, cmp -> endsWith(srcStr, new LV(srcStr, 0, -1), cmp)); }
367
368    /**
369     * <EMBED CLASS=defs DATA-DESC='does not end with any' DATA-CI='is'>
370     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
371     * @param srcStr Any non-null instance of {@code java.lang.String}
372     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
373     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
374     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
375     * @see #NAND(String, String, String[], Predicate)
376     * @see #endsWith(String, LV, String)
377     */
378    public static boolean endsWithNAND(String srcStr, String... tokens)
379    { return NAND("endsWithNAND", srcStr, tokens, cmp -> endsWith(srcStr, new LV(srcStr, 0, -1), cmp)); }
380
381    /**
382     * <EMBED CLASS=defs DATA-DESC='starts with exactly one' DATA-CI='is'>
383     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
384     * @param srcStr Any non-null instance of {@code java.lang.String}
385     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
386     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
387     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
388     * @see #XOR(String, String, String[], Predicate)
389     * @see #startsWith(String, LV, String)
390     */
391    public static boolean startsWithXOR(String srcStr, String... tokens)
392    { return XOR("startsWithXOR", srcStr, tokens, cmp -> startsWith(srcStr, new LV(srcStr, 0, -1), cmp)); }
393
394    /**
395     * <EMBED CLASS=defs DATA-DESC='does not start with any' DATA-CI='is'>
396     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
397     * @param srcStr Any non-null instance of {@code java.lang.String}
398     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
399     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
400     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
401     * @see #NAND(String, String, String[], Predicate)
402     * @see #startsWith(String, LV, String)
403     */
404    public static boolean startsWithNAND(String srcStr, String... tokens)
405    { return NAND("startsWithNAND", srcStr, tokens, cmp -> startsWith(srcStr, new LV(srcStr, 0, -1), cmp)); }
406
407    // ****************************************************************************************
408    // STARTS-WITH, ENDS-WITH - CASE INSENSITIVE
409    // ****************************************************************************************
410
411    /**
412     * <EMBED CLASS=defs DATA-DESC='ends with exactly one' DATA-CI='is not'>
413     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
414     * @param srcStr Any non-null instance of {@code java.lang.String}
415     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
416     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
417     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
418     * @see #endsWithIgnoreCase(String, String)
419     * @see #XOR(String, String, String[], Predicate)
420     */
421    public static boolean endsWithXOR_CI(String srcStr, String... tokens)
422    { return XOR("endsWithXOR_CI", srcStr, tokens, cmp -> endsWithIgnoreCase(srcStr, cmp)); }
423
424    /**
425     * <EMBED CLASS=defs DATA-DESC='does not end with any' DATA-CI='is not'>
426     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
427     * @param srcStr Any non-null instance of {@code java.lang.String}
428     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
429     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
430     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
431     * @see #endsWithIgnoreCase(String, String)
432     * @see #NAND(String, String, String[], Predicate)
433     */
434    public static boolean endsWithNAND_CI(String srcStr, String... tokens)
435    { return NAND("endsWithNAND_CI", srcStr, tokens, cmp -> endsWithIgnoreCase(srcStr, cmp)); }
436
437    /**
438     * <EMBED CLASS=defs DATA-DESC='starts with exactly one' DATA-CI='is not'>
439     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
440     * @param srcStr Any non-null instance of {@code java.lang.String}
441     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
442     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
443     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
444     * @see #startsWithIgnoreCase(String, String)
445     * @see #XOR(String, String, String[], Predicate)
446     */
447    public static boolean startsWithXOR_CI(String srcStr, String... tokens)
448    { return XOR("startsWithXOR_CI", srcStr, tokens, cmp -> startsWithIgnoreCase(srcStr, cmp)); }
449
450    /**
451     * <EMBED CLASS=defs DATA-DESC='does not start with any' DATA-CI='is not'>
452     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
453     * @param srcStr Any non-null instance of {@code java.lang.String}
454     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
455     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
456     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
457     * @see #startsWithIgnoreCase(String, String)
458     * @see #NAND(String, String, String[], Predicate)
459     */
460    public static boolean startsWithNAND_CI(String srcStr, String... tokens)
461    { return NAND("startsWithNAND_CI", srcStr, tokens, cmp -> startsWithIgnoreCase(srcStr, cmp)); }
462
463    // ****************************************************************************************
464    // Three Standard Java Methods, Added Token Checking
465    // ****************************************************************************************
466
467    /**
468     * <EMBED CLASS=defs DATA-FUNC='starts with' DATA-CI='is'>
469     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
470     * @param srcStr Any non-null instance of {@code java.lang.String}
471     * @param token The {@code String} used in the comparison against {@code 'srcStr'}
472     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
473     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
474     */
475    public static boolean startsWith(String srcStr, String token)
476    {
477        return  srcStr.startsWith(token)
478                && (    (token.length() == srcStr.length())
479                    ||  Character.isWhitespace(srcStr.charAt(token.length())));
480    }
481
482    /**
483     * <EMBED CLASS=defs DATA-FUNC='ends with' DATA-CI='is'>
484     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
485     * @param srcStr Any non-null instance of {@code java.lang.String}
486     * @param token The {@code String} used in the comparison against {@code 'srcStr'}
487     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
488     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
489     */
490    public static boolean endsWith(String srcStr, String token)
491    {
492        return  srcStr.endsWith(token)
493                &&  (   (token.length() == srcStr.length())
494                    ||  (Character.isWhitespace(srcStr.charAt(srcStr.length() - token.length() - 1))));
495    }
496
497    /**
498     * <EMBED CLASS=defs DATA-FUNC='contains' DATA-CI='is'>
499     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
500     * @param srcStr Any non-null instance of {@code java.lang.String}
501     * @param token The {@code String} used in the comparison against {@code 'srcStr'}
502     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
503     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
504     */
505    public static boolean contains(String srcStr, String token)
506    { 
507        int tokenLen    = token.length();
508        int loopLen     = srcStr.length() - tokenLen;
509
510        for (int i=0; i <= loopLen; i++)
511
512            if (    srcStr.regionMatches(i, token, 0, tokenLen)
513                &&  (   (i == 0)
514                    ||  Character.isWhitespace(srcStr.charAt(i-1)))
515                &&  (   ((i + tokenLen) == srcStr.length())
516                    ||  Character.isWhitespace(srcStr.charAt(i + tokenLen)))
517                )
518                return true;
519
520        return false;
521    }
522
523    // ****************************************************************************************
524    // IGNORE-CASE METHODS
525    // ****************************************************************************************
526
527    /**
528     * <EMBED CLASS=defs DATA-FUNC='starts with' DATA-CI='is not'>
529     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
530     * @param srcStr Any non-null instance of {@code java.lang.String}
531     * @param token The {@code String} used in the comparison against {@code 'srcStr'}
532     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
533     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
534     */
535    public static boolean startsWithIgnoreCase(String srcStr, String token)
536    {
537        return  srcStr.regionMatches(true, 0, token, 0, token.length())
538                && (    (token.length() == srcStr.length())
539                    ||  Character.isWhitespace(srcStr.charAt(token.length())));
540    }
541
542    /**
543     * <EMBED CLASS=defs DATA-FUNC='ends with' DATA-CI='is not'>
544     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
545     * @param srcStr Any non-null instance of {@code java.lang.String}
546     * @param token The {@code String} used in the comparison against {@code 'srcStr'}
547     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
548     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
549     */
550    public static boolean endsWithIgnoreCase(String srcStr, String token)
551    {
552        int tokenLen = token.length();
553        int startPos = srcStr.length() - tokenLen;
554
555        return  srcStr.regionMatches(true, startPos, token, 0, tokenLen)
556                &&  (   (tokenLen == srcStr.length())
557                    ||  (Character.isWhitespace(srcStr.charAt(startPos - 1))));
558    }
559
560    /**
561     * <EMBED CLASS=defs DATA-FUNC='contains' DATA-CI='is not'>
562     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
563     * @param srcStr Any non-null instance of {@code java.lang.String}
564     * @param token The {@code String} used in the comparison against {@code 'srcStr'}
565     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
566     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
567     * @see #containsIgnoreCase(String, LV, String)
568     */
569    public static boolean containsIgnoreCase(String srcStr, String token)
570    { return containsIgnoreCase(srcStr, new LV(srcStr, 0, srcStr.length()), token); }
571
572
573
574
575
576
577
578
579
580
581
582    // ****************************************************************************************
583    // ****************************************************************************************
584    // ****************************************************************************************
585    // ****************************************************************************************
586    // ****************************************************************************************
587    // StrCmpr Main Section
588    // ****************************************************************************************
589    // ****************************************************************************************
590    // ****************************************************************************************
591    // ****************************************************************************************
592    // ****************************************************************************************
593
594
595
596    // ****************************************************************************************
597    // CONTAINS
598    // ****************************************************************************************
599
600    /**
601     * <EMBED CLASS=defs DATA-DESC='contains at least one' DATA-CI='is'>
602     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
603     * @param srcStr Any non-null instance of {@code java.lang.String}
604     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
605     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
606     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
607     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
608     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
609     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
610     * @see #CONTAINS(boolean, byte, LV, String, String[])
611     */
612    public static boolean containsOR(String srcStr, int sPos, int ePos, String... tokens)
613    {
614        LV l = new LV(srcStr, sPos, ePos);
615        return CONTAINS(false, OR, l, srcStr, tokens);
616    }
617
618    /**
619     * <EMBED CLASS=defs DATA-DESC='contains every one' DATA-CI='is'>
620     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
621     * @param srcStr Any non-null instance of {@code java.lang.String}
622     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
623     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
624     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
625     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
626     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
627     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
628     * @see #CONTAINS(boolean, byte, LV, String, String[])
629     */
630    public static boolean containsAND(String srcStr, int sPos, int ePos, String... tokens)
631    {
632        LV l = new LV(srcStr, sPos, ePos);
633        return CONTAINS(false, AND, l, srcStr, tokens);
634    }
635
636    /**
637     * <EMBED CLASS=defs DATA-DESC='contains exactly one' DATA-CI='is'>
638     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
639     * @param srcStr Any non-null instance of {@code java.lang.String}
640     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
641     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
642     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
643     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
644     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
645     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
646     * @see #CONTAINS(boolean, byte, LV, String, String[])
647     */
648    public static boolean containsXOR(String srcStr, int sPos, int ePos, String... tokens)
649    {
650        LV l = new LV(srcStr, sPos, ePos);
651        return CONTAINS(false, XOR, l, srcStr, tokens);
652    }
653
654    /**
655     * <EMBED CLASS=defs DATA-DESC='does not contain any' DATA-CI='is'>
656     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
657     * @param srcStr Any non-null instance of {@code java.lang.String}
658     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
659     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
660     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
661     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
662     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
663     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
664     * @see #CONTAINS(boolean, byte, LV, String, String[])
665     */
666    public static boolean containsNAND(String srcStr, int sPos, int ePos, String... tokens)
667    {
668        LV l = new LV(srcStr, sPos, ePos);
669        return CONTAINS(false, NAND, l, srcStr, tokens);
670    }
671
672    /**
673     * <EMBED CLASS=defs DATA-DESC='contains at least one' DATA-CI='is not'>
674     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
675     * @param srcStr Any non-null instance of {@code java.lang.String}
676     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
677     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
678     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
679     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
680     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
681     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
682     * @see #CONTAINS(boolean, byte, LV, String, String[])
683     */
684    public static boolean containsOR_CI(String srcStr, int sPos, int ePos, String... tokens)
685    {
686        LV l = new LV(srcStr, sPos, ePos);
687        return CONTAINS(true, OR, l, srcStr, tokens);
688    }
689
690    /**
691     * <EMBED CLASS=defs DATA-DESC='contains every one' DATA-CI='is not'>
692     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
693     * @param srcStr Any non-null instance of {@code java.lang.String}
694     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
695     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
696     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
697     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
698     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
699     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
700     * @see #CONTAINS(boolean, byte, LV, String, String[])
701     */
702    public static boolean containsAND_CI(String srcStr, int sPos, int ePos, String... tokens)
703    {
704        LV l = new LV(srcStr, sPos, ePos);
705        return CONTAINS(true, AND, l, srcStr, tokens);
706    }
707
708    /**
709     * <EMBED CLASS=defs DATA-DESC='contains exactly one' DATA-CI='is not'>
710     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
711     * @param srcStr Any non-null instance of {@code java.lang.String}
712     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
713     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
714     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
715     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
716     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
717     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
718     * @see #CONTAINS(boolean, byte, LV, String, String[])
719     */
720    public static boolean containsXOR_CI(String srcStr, int sPos, int ePos, String... tokens)
721    {
722        LV l = new LV(srcStr, sPos, ePos);
723        return CONTAINS(true, XOR, l, srcStr, tokens);
724    }
725
726    /**
727     * <EMBED CLASS=defs DATA-DESC='does not contain any' DATA-CI='is not'>
728     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
729     * @param srcStr Any non-null instance of {@code java.lang.String}
730     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
731     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
732     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
733     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
734     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
735     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
736     * @see #CONTAINS(boolean, byte, LV, String, String[])
737     */
738    public static boolean containsNAND_CI(String srcStr, int sPos, int ePos, String... tokens)
739    {
740        LV l = new LV(srcStr, sPos, ePos);
741        return CONTAINS(true, NAND, l, srcStr, tokens);
742    }
743
744    // ****************************************************************************************
745    // STARTS-WITH, ENDS-WITH
746    // ****************************************************************************************
747
748    /**
749     * <EMBED CLASS=defs DATA-DESC='ends with exactly one' DATA-CI='is'>
750     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
751     * @param srcStr Any non-null instance of {@code java.lang.String}
752     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
753     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
754     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
755     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
756     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
757     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
758     * @see #endsWith(String, LV, String)
759     * @see #XOR(String, String, String[], Predicate)
760     */
761    public static boolean endsWithXOR(String srcStr, int sPos, int ePos, String... tokens)
762    {
763        LV l = new LV(srcStr, sPos, ePos);
764        return XOR("endsWithXOR", srcStr, tokens, cmp -> endsWith(srcStr, l, cmp));
765    }
766
767    /**
768     * <EMBED CLASS=defs DATA-DESC='does not end with any' DATA-CI='is'>
769     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
770     * @param srcStr Any non-null instance of {@code java.lang.String}
771     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
772     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
773     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
774     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
775     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
776     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
777     * @see #endsWith(String, LV, String)
778     * @see #NAND(String, String, String[], Predicate)
779     */
780    public static boolean endsWithNAND(String srcStr, int sPos, int ePos, String... tokens)
781    {
782        LV l = new LV(srcStr, sPos, ePos);
783        return NAND("endsWithNAND", srcStr, tokens, cmp -> endsWith(srcStr, l, cmp));
784    }
785
786    /**
787     * <EMBED CLASS=defs DATA-DESC='starts with exactly one' DATA-CI='is'>
788     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
789     * @param srcStr Any non-null instance of {@code java.lang.String}
790     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
791     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
792     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
793     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
794     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
795     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
796     * @see #startsWith(String, LV, String)
797     * @see #XOR(String, String, String[], Predicate)
798     */
799    public static boolean startsWithXOR(String srcStr, int sPos, int ePos, String... tokens)
800    {
801        LV l = new LV(srcStr, sPos, ePos);
802        return XOR("startsWithXOR", srcStr, tokens, cmp -> startsWith(srcStr, l, cmp));
803    }
804
805    /**
806     * <EMBED CLASS=defs DATA-DESC='does not start with any' DATA-CI='is'>
807     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
808     * @param srcStr Any non-null instance of {@code java.lang.String}
809     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
810     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
811     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
812     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
813     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
814     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
815     * @see #startsWith(String, LV, String)
816     * @see #NAND(String, String, String[], Predicate)
817     */
818    public static boolean startsWithNAND(String srcStr, int sPos, int ePos, String... tokens)
819    {
820        LV l = new LV(srcStr, sPos, ePos);
821        return NAND("startsWithNAND", srcStr, tokens, cmp -> startsWith(srcStr, l, cmp));
822    }
823
824    // ****************************************************************************************
825    // STARTS-WITH, ENDS-WITH - CASE INSENSITIVE
826    // ****************************************************************************************
827
828    /**
829     * <EMBED CLASS=defs DATA-DESC='ends with exactly one' DATA-CI='is not'>
830     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
831     * @param srcStr Any non-null instance of {@code java.lang.String}
832     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
833     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
834     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
835     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
836     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
837     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
838     * @see #endsWithIgnoreCase(String, LV, String)
839     * @see #XOR(String, String, String[], Predicate)
840     */
841    public static boolean endsWithXOR_CI(String srcStr, int sPos, int ePos, String... tokens)
842    {
843        LV l = new LV(srcStr, sPos, ePos);
844        return XOR("endsWithXOR_CI", srcStr, tokens, cmp -> endsWithIgnoreCase(srcStr, l, cmp));
845    }
846
847    /**
848     * <EMBED CLASS=defs DATA-DESC='does not end with any' DATA-CI='is not'>
849     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
850     * @param srcStr Any non-null instance of {@code java.lang.String}
851     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
852     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
853     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
854     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
855     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
856     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
857     * @see #endsWithIgnoreCase(String, LV, String)
858     * @see #NAND(String, String, String[], Predicate)
859     */
860    public static boolean endsWithNAND_CI(String srcStr, int sPos, int ePos, String... tokens)
861    {
862        LV l = new LV(srcStr, sPos, ePos);
863        return NAND("endsWithNAND_CI", srcStr, tokens, cmp -> endsWithIgnoreCase(srcStr, l, cmp));
864    }
865
866    /**
867     * <EMBED CLASS=defs DATA-DESC='starts with exactly one' DATA-CI='is not'>
868     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
869     * @param srcStr Any non-null instance of {@code java.lang.String}
870     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
871     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
872     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
873     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
874     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
875     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
876     * @see #startsWithIgnoreCase(String, LV, String)
877     * @see #XOR(String, String, String[], Predicate)
878     */
879    public static boolean startsWithXOR_CI(String srcStr, int sPos, int ePos, String... tokens)
880    {
881        LV l = new LV(srcStr, sPos, ePos);
882        return XOR("startsWithXOR_CI", srcStr, tokens, cmp -> startsWithIgnoreCase(srcStr, l, cmp));
883    }
884
885    /**
886     * <EMBED CLASS=defs DATA-DESC='does not start with any' DATA-CI='is not'>
887     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
888     * @param srcStr Any non-null instance of {@code java.lang.String}
889     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
890     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
891     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
892     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
893     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
894     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
895     * @see #startsWithIgnoreCase(String, LV, String)
896     * @see #NAND(String, String, String[], Predicate)
897     */
898    public static boolean startsWithNAND_CI(String srcStr, int sPos, int ePos, String... tokens)
899    {
900        LV l = new LV(srcStr, sPos, ePos);
901        return NAND("startsWithNAND_CI", srcStr, tokens, cmp -> startsWithIgnoreCase(srcStr, l, cmp));
902    }
903
904    // ****************************************************************************************
905    // Starts With, Ends With
906    // ****************************************************************************************
907
908    /**
909     * <EMBED CLASS=defs DATA-FUNC='starts with' DATA-CI='is'>
910     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
911     * @param srcStr Any non-null instance of {@code java.lang.String}
912     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
913     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
914     * @param token The {@code String} used in the comparison against {@code srcStr}
915     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
916     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
917     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
918     * @see #startsWith(String, LV, String)
919     */
920    public static boolean startsWith(String srcStr, int sPos, int ePos, String token)
921    { return startsWith(srcStr, new LV(srcStr, sPos, ePos), token); }
922
923    /**
924     * <EMBED CLASS=defs DATA-FUNC='starts with' DATA-CI='is not'>
925     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
926     * @param srcStr Any non-null instance of {@code java.lang.String}
927     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
928     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
929     * @param token The {@code String} used in the comparison against {@code srcStr}
930     * <EMBED CLASS='external-html' DATA-FILE-ID='SWNODELIM'>
931     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
932     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
933     * @see #startsWithIgnoreCase(String, LV, String)
934     */
935    public static boolean startsWithIgnoreCase(String srcStr, int sPos, int ePos, String token)
936    { return startsWithIgnoreCase(srcStr, new LV(srcStr, sPos, ePos), token); }
937
938    /**
939     * <EMBED CLASS=defs DATA-FUNC='ends with' DATA-CI='is'>
940     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
941     * @param srcStr Any non-null instance of {@code java.lang.String}
942     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
943     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
944     * @param token The {@code String} used in the comparison against {@code srcStr}
945     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
946     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
947     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
948     * @see #endsWith(String, LV, String)
949     */
950    public static boolean endsWith(String srcStr, int sPos, int ePos, String token)
951    { return endsWith(srcStr, new LV(srcStr, sPos, ePos), token); }
952
953    /**
954     * <EMBED CLASS=defs DATA-FUNC='ends with' DATA-CI='is not'>
955     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
956     * @param srcStr Any non-null instance of {@code java.lang.String}
957     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
958     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
959     * @param token The {@code String} used in the comparison against {@code srcStr}
960     * <EMBED CLASS='external-html' DATA-FILE-ID='EWNODELIM'>
961     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
962     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
963     * @see #endsWithIgnoreCase(String, LV, String)
964     */
965    public static boolean endsWithIgnoreCase(String srcStr, int sPos, int ePos, String token)
966    { return endsWithIgnoreCase(srcStr, new LV(srcStr, sPos, ePos), token); }
967
968    /**
969     * <EMBED CLASS=defs DATA-FUNC='contains' DATA-CI='is'>
970     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
971     * @param srcStr Any non-null instance of {@code java.lang.String}
972     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
973     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
974     * @param token The {@code String} used in the comparison against {@code srcStr}
975     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
976     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
977     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
978     * @see #contains(String, LV, String)
979     */
980    public static boolean contains(String srcStr, int sPos, int ePos, String token)
981    { return contains(srcStr, new LV(srcStr, sPos, ePos), token); }
982
983    /**
984     * <EMBED CLASS=defs DATA-FUNC='contains' DATA-CI='is not'>
985     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
986     * @param srcStr Any non-null instance of {@code java.lang.String}
987     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
988     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
989     * @param token The {@code String} used in the comparison against {@code srcStr}
990     * <EMBED CLASS='external-html' DATA-FILE-ID='CNNODELIM'>
991     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
992     * @throws StringIndexOutOfBoundsException <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
993     * @see #containsIgnoreCase(String, LV, String)
994     */
995    public static boolean containsIgnoreCase(String srcStr, int sPos, int ePos, String token)
996    { return containsIgnoreCase(srcStr, new LV(srcStr, sPos, ePos), token); }
997
998    // ****************************************************************************************
999    // LV - protected
1000    // ****************************************************************************************
1001
1002    /**
1003     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
1004     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
1005     */
1006    protected static boolean startsWith(String srcStr, LV l, String token)
1007    {
1008        int tokenLen = token.length();
1009
1010        return      ((l.end - l.start) >= tokenLen) 
1011                &&  srcStr.regionMatches(l.start, token, 0, tokenLen)
1012                &&  (   ((l.start + tokenLen) == srcStr.length())
1013                    ||  Character.isWhitespace(srcStr.charAt(l.start + tokenLen)));
1014    }
1015
1016    /**
1017     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
1018     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
1019     */
1020    protected static boolean startsWithIgnoreCase(String srcStr, LV l, String token)
1021    {
1022        int tokenLen = token.length();
1023
1024        return      ((l.end - l.start) >= tokenLen) 
1025                &&  srcStr.regionMatches(true, l.start, token, 0, tokenLen)
1026                &&  (   ((l.start + tokenLen) == srcStr.length())
1027                    ||  Character.isWhitespace(srcStr.charAt(l.start + tokenLen)));
1028    }
1029
1030    /**
1031     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
1032     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
1033     */
1034    protected static boolean endsWith(String srcStr, LV l, String token)
1035    {
1036        int tokenLen = token.length();
1037
1038        return      ((l.end - l.start) >= tokenLen)
1039                &&  srcStr.regionMatches(l.end - tokenLen, token, 0, tokenLen)
1040                &&  (   ((l.end - tokenLen) == 0)
1041                    ||  Character.isWhitespace(srcStr.charAt(l.end - tokenLen - 1)));
1042    }
1043
1044    /**
1045     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
1046     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
1047     */
1048    protected static boolean endsWithIgnoreCase(String srcStr, LV l, String token)
1049    {
1050        int tokenLen = token.length();
1051    
1052        return      ((l.end - l.start) >= tokenLen)
1053                &&  srcStr.regionMatches(true, l.end - tokenLen, token, 0, tokenLen)
1054                &&  (   ((l.end - tokenLen) == 0)
1055                    ||  Character.isWhitespace(srcStr.charAt(l.end - tokenLen - 1)));
1056    }
1057
1058    /**
1059     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
1060     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
1061     */
1062    protected static boolean contains(String srcStr, LV l, String token)
1063    {
1064        // String.regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
1065        // Tests if two string regions are equal.  A substring of this {@code String} object is
1066        // compared to a substring of the argument other.  The result is true if these substrings
1067        // represent character sequences that are the same, ignoring case if and only if ignoreCase
1068        // is true.
1069
1070        int tokenLen    = token.length();
1071        int loopLen     = l.end - tokenLen;
1072
1073        if ((l.end - l.start) < token.length()) return false;
1074
1075        for (int i=l.start; i <= loopLen; i++)
1076            if (    srcStr.regionMatches(i, token, 0, tokenLen)
1077                &&  (   (i == 0)
1078                    ||  Character.isWhitespace(srcStr.charAt(i-1)))
1079                &&  (   ((i + tokenLen) == srcStr.length())
1080                    ||  Character.isWhitespace(srcStr.charAt(i + tokenLen)))
1081                )
1082                return true;
1083
1084        return false;
1085    }
1086
1087    /**
1088     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
1089     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
1090     */
1091    protected static boolean containsIgnoreCase(String srcStr, LV l, String token)
1092    {
1093        // String.regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
1094        // Tests if two string regions are equal.  A substring of this {@code String} object is
1095        // compared to a substring of the argument other.  The result is true if these substrings
1096        // represent character sequences that are the same, ignoring case if and only if ignoreCase
1097        // is true.
1098
1099        int tokenLen    = token.length();
1100        int loopLen     = l.end - tokenLen;
1101
1102        if ((l.end - l.start) < token.length()) return false;
1103
1104        for (int i=l.start; i <= loopLen; i++)
1105            if (    srcStr.regionMatches(true, i, token, 0, tokenLen)
1106                &&  (   (i == 0)
1107                    ||  Character.isWhitespace(srcStr.charAt(i-1)))
1108                &&  (   ((i + tokenLen) == srcStr.length())
1109                    ||  Character.isWhitespace(srcStr.charAt(i + tokenLen)))
1110                )
1111                return true;
1112
1113        return false;
1114    }
1115
1116    // ****************************************************************************************
1117    // CONTAINS OPTIMIZATION
1118    // ****************************************************************************************
1119
1120    /**
1121     * Signifies that an {@code 'AND'} operation is required, but only for methods that implement
1122     * one of the {@code 'contains'} variants.
1123     */
1124    protected static final byte AND   = 0;
1125
1126    /**
1127     * Signifies that an {@code 'AND'} operation is required, but only for methods that implement
1128     * one of the {@code 'contains'} variants.
1129     */
1130    protected static final byte OR    = 1;
1131
1132    /**
1133     * Signifies that an {@code 'AND'} operation is required, but only for methods that implement
1134     * one of the {@code 'contains'} variants.
1135     */
1136    protected static final byte NAND  = 2;
1137
1138    /**
1139     * Signifies that an {@code 'AND'} operation is required, but only for methods that implement
1140     * one of the {@code 'contains'} variants.
1141     */
1142    protected static final byte XOR   = 3;
1143
1144    private static final String CONTAINS_EX = 
1145        "The value passed to parameter 'booleanOperation' was [BOOL]." +
1146        "However, this parameter is intended to must be chosen from one of the four boolean " +
1147        "static-constants available in this class.  Valid values for this parameter include: " +
1148        "StrCmpr.AND, StrCmpr.OR, StrCmpr.XOR and StrCmpr.NAND.";
1149
1150    /**
1151     * Implementing a 'contains' is more efficient by performing only one loop iteration.
1152     * Therefore, the methods that implement some variant of the {@code String.contains} method
1153     * will use this general-purpose {@code contains}-testing method.
1154     * @param ignoresCase This is used to signify whether to ignore case when performing the
1155     * {@code String}-comparison operations.
1156     * @param booleanOperation This is designed to take one of four values.  This method will
1157     * throw an exception if it does not.
1158     * @param l Loop end-point parameter
1159     * @param srcStr Any non-null instance of {@code java.lang.String}
1160     * @param tokens This is one (or many) java {@code String's}, each of which shall be
1161     * checked whether it is contained by {@code 'srcStr'}.
1162     * @return The appropriate response based on the inputs for boolean logic.
1163     */
1164    protected static boolean CONTAINS(
1165        boolean ignoresCase, byte booleanOperation, LV l, String srcStr, String[] tokens
1166    )
1167    {
1168        int     len         = srcStr.length();
1169        int     count       = (booleanOperation == XOR) ? 0 : tokens.length;
1170        int[]   tokLenArr   = new int[tokens.length];
1171
1172        for (int i=0; i < tokens.length; i++) tokLenArr[i] = tokens[i].length();
1173
1174        for (int i=l.start; i < l.end; i++)
1175
1176            for (int j=0; j < tokens.length; j++)
1177
1178                if (tokLenArr[j] != -1)
1179
1180                    if (srcStr.regionMatches(ignoresCase, i, tokens[j], 0, tokLenArr[j]))
1181
1182                        if (    (   (i==0)
1183                                ||  Character.isWhitespace(srcStr.charAt(i-1)))
1184                            &&  (   ((i + tokLenArr[j]) == len)
1185                                ||  Character.isWhitespace(srcStr.charAt(i + tokLenArr[j])))
1186                        )
1187
1188                            switch (booleanOperation)
1189                            {
1190                                case AND    :   tokLenArr[j] = -1;
1191                                                if (--count == 0)   return true;
1192                                                else                break;
1193
1194                                case XOR    :   tokLenArr[j] = -1;
1195                                                if (++count > 1)    return false;
1196                                                else                break;
1197
1198                                case OR     :   return true;
1199
1200                                case NAND   :   return false;
1201
1202                                default     :   throw new IllegalArgumentException
1203                                                (CONTAINS_EX.replace("BOOL", "" + booleanOperation));
1204                            }
1205
1206        switch(booleanOperation)
1207        {
1208            case AND    : return false;
1209            case OR     : return false;
1210            case XOR    : return count == 1;
1211            case NAND   : return true;
1212            default     : throw new IllegalArgumentException
1213                            (CONTAINS_EX.replace("BOOL", "" + booleanOperation));
1214        }
1215    }
1216
1217    /**
1218     * Implementing a 'contains' is more efficient by performing only one loop iteration.
1219     * Therefore, the methods that implement some variant of the {@code String.contains} method
1220     * will use this general-purpose {@code contains}-testing method.
1221     * @param ignoresCase This is used to signify whether to ignore case when performing the
1222     * {@code String}-comparison operations.
1223     * @param booleanOperation This is designed to take one of four values.  This method will
1224     * throw an exception if it does not.
1225     * @param srcStr Any non-null instance of {@code java.lang.String}
1226     * @param tokens This is one (or many) java {@code String's}, each of which shall be
1227     * checked whether it is contained by {@code 'srcStr'}.
1228     * @return The appropriate response based on the inputs for boolean logic.
1229     */
1230    protected static boolean CONTAINS(
1231        boolean ignoresCase, byte booleanOperation, String srcStr, String[] tokens
1232    )
1233    {
1234        int     len         = srcStr.length();
1235        int     count       = (booleanOperation == XOR) ? 0 : tokens.length;
1236        int[]   tokLenArr   = new int[tokens.length];
1237
1238        for (int i=0; i < tokens.length; i++) tokLenArr[i] = tokens[i].length();
1239
1240        for (int i=0; i < len; i++)
1241
1242            for (int j=0; j < tokens.length; j++)
1243
1244                if (tokLenArr[j] != -1)
1245
1246                    if (srcStr.regionMatches(ignoresCase, i, tokens[j], 0, tokLenArr[j]))
1247
1248                        if (    (   (i==0)
1249                                ||  Character.isWhitespace(srcStr.charAt(i-1)))
1250                            &&  (   ((i + tokens[j].length()) == len)
1251                                ||  Character.isWhitespace(srcStr.charAt(i + tokens[j].length())))
1252                        )
1253                            switch (booleanOperation)
1254                            {
1255                                case AND    :   tokLenArr[j] = -1;
1256                                                if (--count == 0)   return true;
1257                                                else                break;
1258
1259                                case XOR    :   tokLenArr[j] = -1;
1260                                                if (++count > 1)    return false;
1261                                                else                break;
1262
1263                                case OR     :   return true;
1264
1265                                case NAND   :   return false;
1266
1267                                default     :   throw new IllegalArgumentException
1268                                                (CONTAINS_EX.replace("BOOL", "" + booleanOperation));
1269                            }
1270
1271        switch(booleanOperation)
1272        {
1273            case AND    : return false;
1274            case OR     : return false;
1275            case XOR    : return count == 1;
1276            case NAND   : return true;
1277            default     : throw new IllegalArgumentException
1278                            (CONTAINS_EX.replace("BOOL", "" + booleanOperation));
1279        }
1280    }
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307 
1308
1309    // ****************************************************************************************
1310    // ****************************************************************************************
1311    // ****************************************************************************************
1312    // ****************************************************************************************
1313    // ****************************************************************************************
1314    // ****************************************************************************************
1315    // StrCmpr Main Section
1316    // ****************************************************************************************
1317    // ****************************************************************************************
1318    // ****************************************************************************************
1319    // ****************************************************************************************
1320    // ****************************************************************************************
1321
1322
1323    
1324    // ****************************************************************************************
1325    // CONTAINS
1326    // ****************************************************************************************
1327
1328    /**
1329     * <EMBED CLASS=defs DATA-DESC='contains at least one' DATA-CI='is'>
1330     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1331     * @param srcStr Any non-null instance of {@code java.lang.String}
1332     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1333     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1334     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1335     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1336     * @see #CONTAINS(boolean, byte, String, String[])
1337     */
1338    public static boolean containsOR
1339        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1340    { return CONTAINS(false, OR, srcStr, extraDelimiterTest, tokens); }
1341
1342    /**
1343     * <EMBED CLASS=defs DATA-DESC='contains every one' DATA-CI='is'>
1344     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1345     * @param srcStr Any non-null instance of {@code java.lang.String}
1346     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1347     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1348     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1349     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1350     * @see #CONTAINS(boolean, byte, String, String[])
1351     */
1352    public static boolean containsAND
1353        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1354    { return CONTAINS(false, AND, srcStr, extraDelimiterTest, tokens); }
1355
1356    /**
1357     * <EMBED CLASS=defs DATA-DESC='contains exactly one' DATA-CI='is'>
1358     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1359     * @param srcStr Any non-null instance of {@code java.lang.String}
1360     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1361     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1362     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1363     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1364     * @see #CONTAINS(boolean, byte, String, String[])
1365     */
1366    public static boolean containsXOR
1367        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1368    { return CONTAINS(false, XOR, srcStr, extraDelimiterTest, tokens); }
1369
1370    /**
1371     * <EMBED CLASS=defs DATA-DESC='does not contain any' DATA-CI='is'>
1372     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1373     * @param srcStr Any non-null instance of {@code java.lang.String}
1374     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1375     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1376     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1377     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1378     * @see #CONTAINS(boolean, byte, String, String[])
1379     */
1380    public static boolean containsNAND
1381        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1382    { return CONTAINS(false, NAND, srcStr, extraDelimiterTest, tokens); }
1383
1384    /**
1385     * <EMBED CLASS=defs DATA-DESC='contains at least one' DATA-CI='is not'>
1386     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1387     * @param srcStr Any non-null instance of {@code java.lang.String}
1388     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1389     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1390     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1391     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1392     * @see #CONTAINS(boolean, byte, String, String[])
1393     */
1394    public static boolean containsOR_CI
1395        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1396    { return CONTAINS(true, OR, srcStr, extraDelimiterTest, tokens); }
1397
1398    /**
1399     * <EMBED CLASS=defs DATA-DESC='contains every one' DATA-CI='is not'>
1400     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1401     * @param srcStr Any non-null instance of {@code java.lang.String}
1402     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1403     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1404     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1405     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1406     * @see #CONTAINS(boolean, byte, String, String[])
1407     */
1408    public static boolean containsAND_CI
1409        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1410    { return CONTAINS(true, AND, srcStr, extraDelimiterTest, tokens); }
1411
1412    /**
1413     * <EMBED CLASS=defs DATA-DESC='contains exactly one' DATA-CI='is not'>
1414     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1415     * @param srcStr Any non-null instance of {@code java.lang.String}
1416     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1417     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1418     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1419     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1420     * @see #CONTAINS(boolean, byte, String, String[])
1421     */
1422    public static boolean containsXOR_CI
1423        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1424    { return CONTAINS(true, XOR, srcStr, extraDelimiterTest, tokens); }
1425
1426    /**
1427     * <EMBED CLASS=defs DATA-DESC='does not contain any' DATA-CI='is not'>
1428     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1429     * @param srcStr Any non-null instance of {@code java.lang.String}
1430     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1431     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1432     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1433     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1434     * @see #CONTAINS(boolean, byte, String, String[])
1435     */
1436    public static boolean containsNAND_CI
1437        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1438    { return CONTAINS(true, NAND, srcStr, extraDelimiterTest, tokens); }
1439
1440    // ****************************************************************************************
1441    // STARTS-WITH, ENDS-WITH
1442    // ****************************************************************************************
1443
1444    /**
1445     * <EMBED CLASS=defs DATA-DESC='ends with exactly one' DATA-CI='is'>
1446     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1447     * @param srcStr Any non-null instance of {@code java.lang.String}
1448     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1449     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1450     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
1451     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1452     * @see #XOR(String, String, String[], Predicate)
1453     * @see #endsWith(String, LV, String)
1454     */
1455    public static boolean endsWithXOR
1456        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1457    {
1458        return XOR(
1459            "endsWithXOR", srcStr, tokens,
1460            cmp -> endsWith(srcStr, new LV(srcStr, 0, -1), extraDelimiterTest, cmp)
1461        );
1462    }
1463
1464    /**
1465     * <EMBED CLASS=defs DATA-DESC='does not end with any' DATA-CI='is'>
1466     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1467     * @param srcStr Any non-null instance of {@code java.lang.String}
1468     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1469     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1470     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
1471     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1472     * @see #NAND(String, String, String[], Predicate)
1473     * @see #endsWith(String, LV, String)
1474     */
1475    public static boolean endsWithNAND
1476        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1477    {
1478        return NAND(
1479            "endsWithNAND", srcStr, tokens,
1480            cmp -> endsWith(srcStr, new LV(srcStr, 0, -1), extraDelimiterTest, cmp)
1481        );
1482    }
1483
1484    /**
1485     * <EMBED CLASS=defs DATA-DESC='starts with exactly one' DATA-CI='is'>
1486     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1487     * @param srcStr Any non-null instance of {@code java.lang.String}
1488     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1489     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1490     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
1491     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1492     * @see #XOR(String, String, String[], Predicate)
1493     * @see #startsWith(String, LV, String)
1494     */
1495    public static boolean startsWithXOR
1496        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1497    {
1498        return XOR(
1499            "startsWithXOR", srcStr, tokens,
1500            cmp -> startsWith(srcStr, new LV(srcStr, 0, -1), extraDelimiterTest, cmp)
1501        );
1502    }
1503
1504    /**
1505     * <EMBED CLASS=defs DATA-DESC='does not start with any' DATA-CI='is'>
1506     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1507     * @param srcStr Any non-null instance of {@code java.lang.String}
1508     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1509     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1510     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
1511     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1512     * @see #NAND(String, String, String[], Predicate)
1513     * @see #startsWith(String, LV, String)
1514     */
1515    public static boolean startsWithNAND
1516        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1517    {
1518        return NAND(
1519            "startsWithNAND", srcStr, tokens,
1520            cmp -> startsWith(srcStr, new LV(srcStr, 0, -1), extraDelimiterTest, cmp)
1521        );
1522    }
1523
1524    // ****************************************************************************************
1525    // STARTS-WITH, ENDS-WITH - CASE INSENSITIVE
1526    // ****************************************************************************************
1527
1528    /**
1529     * <EMBED CLASS=defs DATA-DESC='ends with exactly one' DATA-CI='is not'>
1530     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1531     * @param srcStr Any non-null instance of {@code java.lang.String}
1532     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1533     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1534     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
1535     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1536     * @see #endsWithIgnoreCase(String, String)
1537     * @see #XOR(String, String, String[], Predicate)
1538     */
1539    public static boolean endsWithXOR_CI
1540        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1541    {
1542        return XOR(
1543            "endsWithXOR_CI", srcStr, tokens,
1544            cmp -> endsWithIgnoreCase(srcStr, extraDelimiterTest, cmp)
1545        );
1546    }
1547
1548    /**
1549     * <EMBED CLASS=defs DATA-DESC='does not end with any' DATA-CI='is not'>
1550     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1551     * @param srcStr Any non-null instance of {@code java.lang.String}
1552     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1553     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1554     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
1555     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1556     * @see #endsWithIgnoreCase(String, String)
1557     * @see #NAND(String, String, String[], Predicate)
1558     */
1559    public static boolean endsWithNAND_CI
1560        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1561    {
1562        return NAND(
1563            "endsWithNAND_CI", srcStr, tokens,
1564            cmp -> endsWithIgnoreCase(srcStr, extraDelimiterTest, cmp)
1565        );
1566    }
1567
1568    /**
1569     * <EMBED CLASS=defs DATA-DESC='starts with exactly one' DATA-CI='is not'>
1570     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1571     * @param srcStr Any non-null instance of {@code java.lang.String}
1572     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1573     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1574     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
1575     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1576     * @see #startsWithIgnoreCase(String, String)
1577     * @see #XOR(String, String, String[], Predicate)
1578     */
1579    public static boolean startsWithXOR_CI
1580        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1581    {
1582        return XOR(
1583            "startsWithXOR_CI", srcStr, tokens,
1584            cmp -> startsWithIgnoreCase(srcStr, extraDelimiterTest, cmp)
1585        );
1586    }
1587
1588    /**
1589     * <EMBED CLASS=defs DATA-DESC='does not start with any' DATA-CI='is not'>
1590     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC>
1591     * @param srcStr Any non-null instance of {@code java.lang.String}
1592     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1593     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1594     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
1595     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET>
1596     * @see #startsWithIgnoreCase(String, String)
1597     * @see #NAND(String, String, String[], Predicate)
1598     */
1599    public static boolean startsWithNAND_CI
1600        (String srcStr, Predicate<Character> extraDelimiterTest, String... tokens)
1601    {
1602        return NAND(
1603            "startsWithNAND_CI", srcStr, tokens,
1604            cmp -> startsWithIgnoreCase(srcStr, extraDelimiterTest, cmp)
1605        );
1606    }
1607
1608
1609    // ****************************************************************************************
1610    // Three Standard Java Methods, Added Token Checking
1611    // ****************************************************************************************
1612
1613    /**
1614     * <EMBED CLASS=defs DATA-FUNC='starts with' DATA-CI='is'>
1615     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
1616     * @param srcStr Any non-null instance of {@code java.lang.String}
1617     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1618     * @param token The {@code String} used in the comparison against {@code srcStr}
1619     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
1620     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
1621     */
1622    public static boolean startsWith
1623        (String srcStr, Predicate<Character> extraDelimiterTest, String token)
1624    {
1625        return  srcStr.startsWith(token)
1626                &&  (   (token.length() == srcStr.length())
1627                    ||  Character.isWhitespace(srcStr.charAt(token.length()))
1628                    ||  extraDelimiterTest.test(srcStr.charAt(token.length())));
1629    }
1630
1631    /**
1632     * <EMBED CLASS=defs DATA-FUNC='ends with' DATA-CI='is'>
1633     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
1634     * @param srcStr Any non-null instance of {@code java.lang.String}
1635     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1636     * @param token The {@code String} used in the comparison against {@code srcStr}
1637     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
1638     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
1639     */
1640    public static boolean endsWith
1641        (String srcStr, Predicate<Character> extraDelimiterTest, String token)
1642    {
1643        int tokenLen = token.length();
1644
1645        return  srcStr.endsWith(token)
1646                &&  (   ((srcStr.length() - tokenLen) == 0)
1647                    ||  Character.isWhitespace(srcStr.charAt(srcStr.length() - tokenLen - 1))
1648                    ||  extraDelimiterTest.test(srcStr.charAt(srcStr.length() - tokenLen - 1)));
1649    }
1650
1651    /**
1652     * <EMBED CLASS=defs DATA-FUNC='contains' DATA-CI='is'>
1653     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
1654     * @param srcStr Any non-null instance of {@code java.lang.String}
1655     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1656     * @param token The {@code String} used in the comparison against {@code srcStr}
1657     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1658     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
1659     */
1660    public static boolean contains
1661        (String srcStr, Predicate<Character> extraDelimiterTest, String token)
1662    { 
1663        int tokenLen    = token.length();
1664        int loopLen     = srcStr.length() - tokenLen;
1665
1666        for (int i=0; i <= loopLen; i++)
1667
1668            if (    srcStr.regionMatches(i, token, 0, tokenLen)
1669                &&  (   (i == 0)
1670                    ||  Character.isWhitespace(srcStr.charAt(i - 1))
1671                    ||  extraDelimiterTest.test(srcStr.charAt(i - 1)))
1672                &&  (   ((i + tokenLen) == srcStr.length())
1673                    ||  Character.isWhitespace(srcStr.charAt(i + tokenLen))
1674                    ||  extraDelimiterTest.test(srcStr.charAt(i + tokenLen)))
1675                )
1676
1677                return true;
1678
1679        return false;
1680    }
1681
1682    // ****************************************************************************************
1683    // IGNORE-CASE METHODS
1684    // ****************************************************************************************
1685
1686    /**
1687     * <EMBED CLASS=defs DATA-FUNC='starts with' DATA-CI='is not'>
1688     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
1689     * @param srcStr Any non-null instance of {@code java.lang.String}
1690     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1691     * @param token The {@code String} used in the comparison against {@code srcStr}
1692     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
1693     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
1694     */
1695    public static boolean startsWithIgnoreCase
1696        (String srcStr, Predicate<Character> extraDelimiterTest, String token)
1697    {
1698        return  srcStr.regionMatches(true, 0, token, 0, token.length())
1699                &&  (   (token.length() == srcStr.length())
1700                    ||  Character.isWhitespace(srcStr.charAt(token.length()))
1701                    ||  extraDelimiterTest.test(srcStr.charAt(token.length())));
1702    }
1703
1704    /**
1705     * <EMBED CLASS=defs DATA-FUNC='ends with' DATA-CI='is not'>
1706     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
1707     * @param srcStr Any non-null instance of {@code java.lang.String}
1708     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1709     * @param token The {@code String} used in the comparison against {@code srcStr}
1710     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
1711     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
1712     */
1713    public static boolean endsWithIgnoreCase
1714        (String srcStr, Predicate<Character> extraDelimiterTest, String token)
1715    {
1716        int tokenLen = token.length();
1717
1718        return  srcStr.regionMatches(true, srcStr.length() - tokenLen, token, 0, tokenLen)
1719                &&  (   ((srcStr.length() - tokenLen) == 0)
1720                    ||  Character.isWhitespace(srcStr.charAt(srcStr.length() - tokenLen - 1))
1721                    ||  extraDelimiterTest.test(srcStr.charAt(srcStr.length() - tokenLen - 1)));
1722    }
1723
1724    /**
1725     * <EMBED CLASS=defs DATA-FUNC='contains' DATA-CI='is not'>
1726     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C>
1727     * @param srcStr Any non-null instance of {@code java.lang.String}
1728     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1729     * @param token The {@code String} used in the comparison against {@code srcStr}
1730     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1731     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C>
1732     * @see #containsIgnoreCase(String, LV, String)
1733     */
1734    public static boolean containsIgnoreCase
1735        (String srcStr, Predicate<Character> extraDelimiterTest, String token)
1736    {
1737        return containsIgnoreCase
1738            (srcStr, new LV(srcStr, 0, srcStr.length()), extraDelimiterTest, token);
1739    }
1740
1741
1742
1743
1744
1745
1746
1747    // ****************************************************************************************
1748    // ****************************************************************************************
1749    // ****************************************************************************************
1750    // ****************************************************************************************
1751    // ****************************************************************************************
1752    // StrCmpr Main Section
1753    // ****************************************************************************************
1754    // ****************************************************************************************
1755    // ****************************************************************************************
1756    // ****************************************************************************************
1757    // ****************************************************************************************
1758
1759
1760
1761    // ****************************************************************************************
1762    // CONTAINS - Case Sensitive
1763    // ****************************************************************************************
1764
1765    /**
1766     * <EMBED CLASS=defs DATA-DESC='contains at least one' DATA-CI='is'>
1767     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1768     * @param srcStr Any non-null instance of {@code java.lang.String}
1769     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1770     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1771     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1772     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1773     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1774     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1775     * @throws StringIndexOutOfBoundsException
1776     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1777     * @see #CONTAINS(boolean, byte, LV, String, String[])
1778     */
1779    public static boolean containsOR(
1780        String srcStr, int sPos, int ePos,
1781        Predicate<Character> extraDelimiterTest, String... tokens
1782    )
1783    {
1784        LV l = new LV(srcStr, sPos, ePos);
1785        return CONTAINS(false, OR, l, srcStr, extraDelimiterTest, tokens);
1786    }
1787
1788    /**
1789     * <EMBED CLASS=defs DATA-DESC='contains every one' DATA-CI='is'>
1790     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1791     * @param srcStr Any non-null instance of {@code java.lang.String}
1792     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1793     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1794     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1795     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1796     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1797     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1798     * @throws StringIndexOutOfBoundsException
1799     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1800     * @see #CONTAINS(boolean, byte, LV, String, String[])
1801     */
1802    public static boolean containsAND(
1803        String srcStr, int sPos, int ePos,
1804        Predicate<Character> extraDelimiterTest, String... tokens)
1805    {
1806        LV l = new LV(srcStr, sPos, ePos);
1807        return CONTAINS(false, AND, l, srcStr, extraDelimiterTest, tokens);
1808    }
1809
1810    /**
1811     * <EMBED CLASS=defs DATA-DESC='contains exactly one' DATA-CI='is'>
1812     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1813     * @param srcStr Any non-null instance of {@code java.lang.String}
1814     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1815     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1816     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1817     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1818     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1819     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1820     * @throws StringIndexOutOfBoundsException
1821     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1822     * @see #CONTAINS(boolean, byte, LV, String, String[])
1823     */
1824    public static boolean containsXOR(
1825        String srcStr, int sPos, int ePos,
1826        Predicate<Character> extraDelimiterTest, String... tokens
1827    )
1828    {
1829        LV l = new LV(srcStr, sPos, ePos);
1830        return CONTAINS(false, XOR, l, srcStr, extraDelimiterTest, tokens);
1831    }
1832
1833    /**
1834     * <EMBED CLASS=defs DATA-DESC='does not contain any' DATA-CI='is'>
1835     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1836     * @param srcStr Any non-null instance of {@code java.lang.String}
1837     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1838     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1839     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1840     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1841     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1842     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1843     * @throws StringIndexOutOfBoundsException
1844     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1845     * @see #CONTAINS(boolean, byte, LV, String, String[])
1846     */
1847    public static boolean containsNAND(
1848        String srcStr, int sPos, int ePos,
1849        Predicate<Character> extraDelimiterTest, String... tokens
1850    )
1851    {
1852        LV l = new LV(srcStr, sPos, ePos);
1853        return CONTAINS(false, NAND, l, srcStr, extraDelimiterTest, tokens);
1854    }
1855
1856    // ****************************************************************************************
1857    // CONTAINS - Case In-Sensitive
1858    // ****************************************************************************************
1859
1860    /**
1861     * <EMBED CLASS=defs DATA-DESC='contains at least one' DATA-CI='is not'>
1862     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1863     * @param srcStr Any non-null instance of {@code java.lang.String}
1864     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1865     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1866     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1867     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1868     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1869     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1870     * @throws StringIndexOutOfBoundsException
1871     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1872     * @see #CONTAINS(boolean, byte, LV, String, String[])
1873     */
1874    public static boolean containsOR_CI(
1875        String srcStr, int sPos, int ePos,
1876        Predicate<Character> extraDelimiterTest, String... tokens
1877    )
1878    {
1879        LV l = new LV(srcStr, sPos, ePos);
1880        return CONTAINS(true, OR, l, srcStr, extraDelimiterTest, tokens);
1881    }
1882
1883    /**
1884     * <EMBED CLASS=defs DATA-DESC='contains every one' DATA-CI='is not'>
1885     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1886     * @param srcStr Any non-null instance of {@code java.lang.String}
1887     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1888     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1889     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1890     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1891     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1892     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1893     * @throws StringIndexOutOfBoundsException
1894     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1895     * @see #CONTAINS(boolean, byte, LV, String, String[])
1896     */
1897    public static boolean containsAND_CI(
1898        String srcStr, int sPos, int ePos,
1899        Predicate<Character> extraDelimiterTest, String... tokens
1900    )
1901    {
1902        LV l = new LV(srcStr, sPos, ePos);
1903        return CONTAINS(true, AND, l, srcStr, extraDelimiterTest, tokens);
1904    }
1905
1906    /**
1907     * <EMBED CLASS=defs DATA-DESC='contains exactly one' DATA-CI='is not'>
1908     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1909     * @param srcStr Any non-null instance of {@code java.lang.String}
1910     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1911     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1912     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1913     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1914     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1915     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1916     * @throws StringIndexOutOfBoundsException
1917     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1918     * @see #CONTAINS(boolean, byte, LV, String, String[])
1919     */
1920    public static boolean containsXOR_CI(
1921        String srcStr, int sPos, int ePos,
1922        Predicate<Character> extraDelimiterTest, String... tokens
1923    )
1924    {
1925        LV l = new LV(srcStr, sPos, ePos);
1926        return CONTAINS(true, XOR, l, srcStr, extraDelimiterTest, tokens);
1927    }
1928
1929    /**
1930     * <EMBED CLASS=defs DATA-DESC='does not contain any' DATA-CI='is not'>
1931     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1932     * @param srcStr Any non-null instance of {@code java.lang.String}
1933     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1934     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1935     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1936     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1937     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
1938     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1939     * @throws StringIndexOutOfBoundsException
1940     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1941     * @see #CONTAINS(boolean, byte, LV, String, String[])
1942     */
1943    public static boolean containsNAND_CI(
1944        String srcStr, int sPos, int ePos,
1945        Predicate<Character> extraDelimiterTest, String... tokens
1946    )
1947    {
1948        LV l = new LV(srcStr, sPos, ePos);
1949
1950        return CONTAINS(true, NAND, l, srcStr, extraDelimiterTest, tokens);
1951    }
1952
1953    // ****************************************************************************************
1954    // STARTS-WITH, ENDS-WITH, Case-Sensitive
1955    // ****************************************************************************************
1956
1957    /**
1958     * <EMBED CLASS=defs DATA-DESC='ends with exactly one' DATA-CI='is'>
1959     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1960     * @param srcStr Any non-null instance of {@code java.lang.String}
1961     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1962     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1963     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1964     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1965     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
1966     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1967     * @throws StringIndexOutOfBoundsException
1968     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1969     * @see #endsWith(String, LV, String)
1970     * @see #XOR(String, String, String[], Predicate)
1971     */
1972    public static boolean endsWithXOR(
1973        String srcStr, int sPos, int ePos,
1974        Predicate<Character> extraDelimiterTest, String... tokens
1975    )
1976    {
1977        LV l = new LV(srcStr, sPos, ePos);
1978
1979        return XOR(
1980            "endsWithXOR", srcStr, tokens,
1981            cmp -> endsWith(srcStr, l, extraDelimiterTest, cmp)
1982        );
1983    }
1984
1985    /**
1986     * <EMBED CLASS=defs DATA-DESC='does not end with any' DATA-CI='is'>
1987     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
1988     * @param srcStr Any non-null instance of {@code java.lang.String}
1989     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
1990     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
1991     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
1992     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
1993     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
1994     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
1995     * @throws StringIndexOutOfBoundsException
1996     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
1997     * @see #endsWith(String, LV, String)
1998     * @see #NAND(String, String, String[], Predicate)
1999     */
2000    public static boolean endsWithNAND(
2001        String srcStr, int sPos, int ePos,
2002        Predicate<Character> extraDelimiterTest, String... tokens
2003    )
2004    {
2005        LV l = new LV(srcStr, sPos, ePos);
2006
2007        return NAND(
2008            "endsWithNAND", srcStr, tokens,
2009            cmp -> endsWith(srcStr, l, extraDelimiterTest, cmp)
2010        );
2011    }
2012
2013    /**
2014     * <EMBED CLASS=defs DATA-DESC='starts with exactly one' DATA-CI='is'>
2015     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
2016     * @param srcStr Any non-null instance of {@code java.lang.String}
2017     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2018     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2019     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2020     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
2021     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
2022     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
2023     * @throws StringIndexOutOfBoundsException
2024     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2025     * @see #startsWith(String, LV, String)
2026     * @see #XOR(String, String, String[], Predicate)
2027     */
2028    public static boolean startsWithXOR(
2029        String srcStr, int sPos, int ePos,
2030        Predicate<Character> extraDelimiterTest, String... tokens
2031    )
2032    {
2033        LV l = new LV(srcStr, sPos, ePos);
2034
2035        return XOR(
2036            "startsWithXOR", srcStr, tokens,
2037            cmp -> startsWith(srcStr, l, extraDelimiterTest, cmp)
2038        );
2039    }
2040
2041    /**
2042     * <EMBED CLASS=defs DATA-DESC='does not start with any' DATA-CI='is'>
2043     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
2044     * @param srcStr Any non-null instance of {@code java.lang.String}
2045     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2046     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2047     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2048     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
2049     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
2050     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
2051     * @throws StringIndexOutOfBoundsException
2052     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2053     * @see #startsWith(String, LV, String)
2054     * @see #NAND(String, String, String[], Predicate)
2055     */
2056    public static boolean startsWithNAND(
2057        String srcStr, int sPos, int ePos,
2058        Predicate<Character> extraDelimiterTest, String... tokens
2059    )
2060    {
2061        LV l = new LV(srcStr, sPos, ePos);
2062
2063        return NAND(
2064            "startsWithNAND", srcStr, tokens,
2065            cmp -> startsWith(srcStr, l, extraDelimiterTest, cmp)
2066        );
2067    }
2068
2069    // ****************************************************************************************
2070    // STARTS-WITH, ENDS-WITH - CASE INSENSITIVE
2071    // ****************************************************************************************
2072
2073    /**
2074     * <EMBED CLASS=defs DATA-DESC='ends with exactly one' DATA-CI='is not'>
2075     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
2076     * @param srcStr Any non-null instance of {@code java.lang.String}
2077     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2078     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2079     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2080     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
2081     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
2082     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
2083     * @throws StringIndexOutOfBoundsException
2084     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2085     * @see #endsWithIgnoreCase(String, LV, String)
2086     * @see #XOR(String, String, String[], Predicate)
2087     */
2088    public static boolean endsWithXOR_CI(
2089        String srcStr, int sPos, int ePos,
2090        Predicate<Character> extraDelimiterTest, String... tokens
2091    )
2092    {
2093        LV l = new LV(srcStr, sPos, ePos);
2094
2095        return XOR(
2096            "endsWithXOR_CI", srcStr, tokens,
2097            cmp -> endsWithIgnoreCase(srcStr, l, extraDelimiterTest, cmp)
2098        );
2099    }
2100
2101    /**
2102     * <EMBED CLASS=defs DATA-DESC='does not ends with any' DATA-CI='is not'>
2103     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
2104     * @param srcStr Any non-null instance of {@code java.lang.String}
2105     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2106     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2107     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2108     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
2109     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
2110     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
2111     * @throws StringIndexOutOfBoundsException
2112     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2113     * @see #endsWithIgnoreCase(String, LV, String)
2114     * @see #NAND(String, String, String[], Predicate)
2115     */
2116    public static boolean endsWithNAND_CI(
2117        String srcStr, int sPos, int ePos,
2118        Predicate<Character> extraDelimiterTest, String... tokens
2119    )
2120    {
2121        LV l = new LV(srcStr, sPos, ePos);
2122
2123        return NAND(
2124            "endsWithNAND_CI", srcStr, tokens,
2125            cmp -> endsWithIgnoreCase(srcStr, l, extraDelimiterTest, cmp)
2126        );
2127    }
2128
2129    /**
2130     * <EMBED CLASS=defs DATA-DESC='starts with exactly one' DATA-CI='is not'>
2131     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
2132     * @param srcStr Any non-null instance of {@code java.lang.String}
2133     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2134     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2135     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2136     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
2137     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
2138     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
2139     * @throws StringIndexOutOfBoundsException
2140     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2141     * @see #startsWithIgnoreCase(String, LV, String)
2142     * @see #XOR(String, String, String[], Predicate)
2143     */
2144    public static boolean startsWithXOR_CI(
2145        String srcStr, int sPos, int ePos,
2146        Predicate<Character> extraDelimiterTest, String... tokens
2147    )
2148    {
2149        LV l = new LV(srcStr, sPos, ePos);
2150
2151        return XOR(
2152            "startsWithXOR_CI", srcStr, tokens,
2153            cmp -> startsWithIgnoreCase(srcStr, l, extraDelimiterTest, cmp)
2154        );
2155    }
2156
2157    /**
2158     * <EMBED CLASS=defs DATA-DESC='does not start with any' DATA-CI='is not'>
2159     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_SE>
2160     * @param srcStr Any non-null instance of {@code java.lang.String}
2161     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2162     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2163     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2164     * @param tokens The {@code String's} used in the comparison against {@code 'srcStr'}
2165     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
2166     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_SE>
2167     * @throws StringIndexOutOfBoundsException
2168     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2169     * @see #startsWithIgnoreCase(String, LV, String)
2170     * @see #NAND(String, String, String[], Predicate)
2171     */
2172    public static boolean startsWithNAND_CI(
2173        String srcStr, int sPos, int ePos,
2174        Predicate<Character> extraDelimiterTest, String... tokens
2175    )
2176    {
2177        LV l = new LV(srcStr, sPos, ePos);
2178
2179        return NAND(
2180            "startsWithNAND_CI", srcStr, tokens,
2181            cmp -> startsWithIgnoreCase(srcStr, l, extraDelimiterTest, cmp)
2182        );
2183    }
2184
2185    // ****************************************************************************************
2186    // simple, with "extra-delimiter"
2187    // ****************************************************************************************
2188
2189    /**
2190     * <EMBED CLASS=defs DATA-FUNC='starts with' DATA-CI='is'>
2191     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
2192     * @param srcStr Any non-null instance of {@code java.lang.String}
2193     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2194     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2195     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2196     * @param token The {@code String} used in the comparison against {@code srcStr}
2197     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
2198     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
2199     * @throws StringIndexOutOfBoundsException
2200     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2201     * @see #startsWith(String, LV, String)
2202     */
2203    public static boolean startsWith
2204        (String srcStr, int sPos, int ePos, Predicate<Character> extraDelimiterTest, String token)
2205    { return startsWith(srcStr, new LV(srcStr, sPos, ePos), extraDelimiterTest, token); }
2206
2207    /**
2208     * <EMBED CLASS=defs DATA-FUNC='starts with' DATA-CI='is not'>
2209     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
2210     * @param srcStr Any non-null instance of {@code java.lang.String}
2211     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2212     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2213     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2214     * @param token The {@code String} used in the comparison against {@code srcStr}
2215     * <EMBED CLASS='external-html' DATA-FILE-ID='SWDELIM'>
2216     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
2217     * @throws StringIndexOutOfBoundsException
2218     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2219     * @see #startsWithIgnoreCase(String, LV, String)
2220     */
2221    public static boolean startsWithIgnoreCase
2222        (String srcStr, int sPos, int ePos, Predicate<Character> extraDelimiterTest, String token)
2223    { return startsWithIgnoreCase(srcStr, new LV(srcStr, sPos, ePos), extraDelimiterTest, token); }
2224
2225    /**
2226     * <EMBED CLASS=defs DATA-FUNC='ends with' DATA-CI='is'>
2227     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
2228     * @param srcStr Any non-null instance of {@code java.lang.String}
2229     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2230     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2231     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2232     * @param token The {@code String} used in the comparison against {@code srcStr}
2233     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
2234     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
2235     * @throws StringIndexOutOfBoundsException
2236     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2237     * @see #endsWith(String, LV, String)
2238     */
2239    public static boolean endsWith
2240        (String srcStr, int sPos, int ePos, Predicate<Character> extraDelimiterTest, String token)
2241    { return endsWith(srcStr, new LV(srcStr, sPos, ePos), extraDelimiterTest, token); }
2242
2243    /**
2244     * <EMBED CLASS=defs DATA-FUNC='ends with' DATA-CI='is not'>
2245     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
2246     * @param srcStr Any non-null instance of {@code java.lang.String}
2247     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2248     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2249     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2250     * @param token The {@code String} used in the comparison against {@code srcStr}
2251     * <EMBED CLASS='external-html' DATA-FILE-ID='EWDELIM'>
2252     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
2253     * @throws StringIndexOutOfBoundsException
2254     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2255     * @see #endsWithIgnoreCase(String, LV, String)
2256     */
2257    public static boolean endsWithIgnoreCase
2258        (String srcStr, int sPos, int ePos, Predicate<Character> extraDelimiterTest, String token)
2259    { return endsWithIgnoreCase(srcStr, new LV(srcStr, sPos, ePos), extraDelimiterTest, token); }
2260
2261    /**
2262     * <EMBED CLASS=defs DATA-FUNC='contains' DATA-CI='is'>
2263     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
2264     * @param srcStr Any non-null instance of {@code java.lang.String}
2265     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2266     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2267     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2268     * @param token The {@code String} used in the comparison against {@code srcStr}
2269     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
2270     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
2271     * @throws StringIndexOutOfBoundsException
2272     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2273     * @see #contains(String, LV, String)
2274     */
2275    public static boolean contains
2276        (String srcStr, int sPos, int ePos, Predicate<Character> extraDelimiterTest, String token)
2277    { return contains(srcStr, new LV(srcStr, sPos, ePos), extraDelimiterTest, token); }
2278
2279    /**
2280     * <EMBED CLASS=defs DATA-FUNC='contains' DATA-CI='is not'>
2281     * <EMBED CLASS='external-html' DATA-FILE-ID=STC_DESC_1C_SE>
2282     * @param srcStr Any non-null instance of {@code java.lang.String}
2283     * @param sPos <EMBED CLASS="external-html" DATA-FILE-ID="SPOSSTR">
2284     * @param ePos <EMBED CLASS="external-html" DATA-FILE-ID="EPOSSTR">
2285     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2286     * @param token The {@code String} used in the comparison against {@code srcStr}
2287     * <EMBED CLASS='external-html' DATA-FILE-ID='CNDELIM'>
2288     * @return <EMBED CLASS='external-html' DATA-FILE-ID=STC_RET_1C_SE>
2289     * @throws StringIndexOutOfBoundsException
2290     * <EMBED CLASS="external-html" DATA-FILE-ID="SIOOBEX">
2291     * @see #containsIgnoreCase(String, LV, String)
2292     */
2293    public static boolean containsIgnoreCase
2294        (String srcStr, int sPos, int ePos, Predicate<Character> extraDelimiterTest, String token)
2295    { return containsIgnoreCase(srcStr, new LV(srcStr, sPos, ePos), extraDelimiterTest, token); }
2296
2297    // ****************************************************************************************
2298    // PROTECTED, LV, Extra-Delimiter
2299    // ****************************************************************************************
2300
2301    /**
2302     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
2303     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
2304     */
2305    protected static boolean startsWith
2306        (String srcStr, LV l, Predicate<Character> extraDelimiterTest, String token)
2307    {
2308        int tokenLen = token.length();
2309
2310        return      ((l.end - l.start) >= tokenLen) 
2311                &&  srcStr.regionMatches(l.start, token, 0, tokenLen)
2312                &&  (   ((l.start + tokenLen) == srcStr.length())
2313                    ||  Character.isWhitespace(srcStr.charAt(l.start + tokenLen))
2314                    ||  extraDelimiterTest.test(srcStr.charAt(l.start + tokenLen)));
2315    }
2316
2317    /**
2318     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
2319     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
2320     */
2321    protected static boolean startsWithIgnoreCase
2322        (String srcStr, LV l, Predicate<Character> extraDelimiterTest, String token)
2323    {
2324        int tokenLen = token.length();
2325
2326        return      ((l.end - l.start) >= tokenLen) 
2327                &&  srcStr.regionMatches(true, l.start, token, 0, tokenLen)
2328                &&  (   ((l.start + tokenLen) == srcStr.length())
2329                    ||  Character.isWhitespace(srcStr.charAt(l.start + tokenLen))
2330                    ||  extraDelimiterTest.test(srcStr.charAt(l.start + tokenLen)));
2331    }
2332
2333    /**
2334     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
2335     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
2336     */
2337    protected static boolean endsWith
2338        (String srcStr, LV l, Predicate<Character> extraDelimiterTest, String token)
2339    {
2340        int tokenLen = token.length();
2341
2342        return      ((l.end - l.start) >= tokenLen)
2343                &&  srcStr.regionMatches(l.end - tokenLen, token, 0, tokenLen)
2344                &&  (   ((l.end - tokenLen) == 0)
2345                    ||  Character.isWhitespace(srcStr.charAt(l.end - tokenLen - 1))
2346                    ||  extraDelimiterTest.test(srcStr.charAt(l.end - tokenLen - 1)));
2347    }
2348
2349    /**
2350     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
2351     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
2352     */
2353    protected static boolean endsWithIgnoreCase
2354        (String srcStr, LV l, Predicate<Character> extraDelimiterTest, String token)
2355    {
2356        int tokenLen = token.length();
2357    
2358        return      ((l.end - l.start) >= tokenLen)
2359                &&  srcStr.regionMatches(true, l.end - tokenLen, token, 0, tokenLen)
2360                &&  (   ((l.end - tokenLen) == 0)
2361                    ||  Character.isWhitespace(srcStr.charAt(l.end - tokenLen - 1))
2362                    ||  extraDelimiterTest.test(srcStr.charAt(l.end - tokenLen - 1)));
2363    }
2364
2365    /**
2366     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
2367     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
2368     */
2369    protected static boolean contains
2370        (String srcStr, LV l, Predicate<Character> extraDelimiterTest, String token)
2371    {
2372        // String.regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
2373        // Tests if two string regions are equal.  A substring of this {@code String} object is
2374        // compared to a substring of the argument other.  The result is true if these substrings
2375        // represent character sequences that are the same, ignoring case if and only if ignoreCase
2376        // is true.
2377
2378        int tokenLen    = token.length();
2379        int loopLen     = l.end - tokenLen;
2380
2381        if ((l.end - l.start) < token.length()) return false;
2382
2383        for (int i=l.start; i <= loopLen; i++)
2384            if (    srcStr.regionMatches(i, token, 0, tokenLen)
2385                &&  (   (i == 0)
2386                    ||  Character.isWhitespace(srcStr.charAt(i-1))
2387                    ||  extraDelimiterTest.test(srcStr.charAt(i-1)))
2388                &&  (   ((i + tokenLen) == srcStr.length())
2389                    ||  Character.isWhitespace(srcStr.charAt(i + tokenLen))
2390                    ||  extraDelimiterTest.test(srcStr.charAt(i + tokenLen)))
2391                )
2392                return true;
2393
2394        return false;
2395    }
2396
2397    /**
2398     * This method remains {@code 'protected'} because it utilizes a specialized Loop-Control
2399     * Variable Class Version of {@code 'LV'}.  It is used internally by the search methods above.
2400     */
2401    protected static boolean containsIgnoreCase
2402        (String srcStr, LV l, Predicate<Character> extraDelimiterTest, String token)
2403    {
2404        // String.regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
2405        // Tests if two string regions are equal.  A substring of this {@code String} object is
2406        // compared to a substring of the argument other.  The result is true if these substrings
2407        // represent character sequences that are the same, ignoring case if and only if ignoreCase
2408        // is true.
2409
2410        int tokenLen    = token.length();
2411        int loopLen     = l.end - tokenLen;
2412
2413        if ((l.end - l.start) < token.length()) return false;
2414
2415        for (int i=l.start; i <= loopLen; i++)
2416            if (    srcStr.regionMatches(true, i, token, 0, tokenLen)
2417                &&  (   (i == 0)
2418                    ||  Character.isWhitespace(srcStr.charAt(i-1))
2419                    ||  extraDelimiterTest.test(srcStr.charAt(i-1)))
2420                &&  (   ((i + tokenLen) == srcStr.length())
2421                    ||  Character.isWhitespace(srcStr.charAt(i + tokenLen))
2422                    ||  extraDelimiterTest.test(srcStr.charAt(i + tokenLen)))
2423                )
2424                return true;
2425
2426        return false;
2427    }
2428
2429    // ****************************************************************************************
2430    // PROTECTED, CONTAINS,  Ezekiel 25:17, Grave-Vengeance and Furious Anger
2431    // ****************************************************************************************
2432
2433
2434    /**
2435     * Implementing a 'contains' is more efficient by performing only one loop iteration.
2436     * Therefore, the methods that implement some variant of the {@code String.contains} method
2437     * will use this general-purpose {@code contains}-testing method.
2438     * @param ignoresCase This is used to signify whether to ignore case when performing the
2439     * {@code String}-comparison operations.
2440     * @param booleanOperation This is designed to take one of four values.  This method will
2441     * throw an exception if it does not.
2442     * @param l Loop end-point parameter
2443     * @param srcStr Any non-null instance of {@code java.lang.String}
2444     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2445     * @param tokens This is one (or many) java {@code String's}, each of which shall be
2446     * checked whether it is contained by {@code 'srcStr'}.
2447     * @return The appropriate response based on the inputs for boolean logic.
2448     */
2449    protected static boolean CONTAINS(
2450        boolean ignoresCase, byte booleanOperation, LV l, String srcStr,
2451        Predicate<Character> extraDelimiterTest, String[] tokens
2452    )
2453    {
2454        int     len         = srcStr.length();
2455        int     count       = (booleanOperation == XOR) ? 0 : tokens.length;
2456        int[]   tokLenArr   = new int[tokens.length];
2457        
2458        for (int i=0; i < tokLenArr.length; i++) tokLenArr[i] = tokens[i].length();
2459
2460        for (int i=l.start; i < l.end; i++)
2461            for (int j=0; j < tokens.length; j++)
2462                if (tokLenArr[j] != -1)
2463                    if (srcStr.regionMatches(ignoresCase, i, tokens[j], 0, tokLenArr[j]))
2464                        if (    (   (i==0)
2465                                ||  Character.isWhitespace(srcStr.charAt(i-1))
2466                                ||  extraDelimiterTest.test(srcStr.charAt(i-1)))
2467                            &&  (   ((i + tokLenArr[j]) == len)
2468                                ||  Character.isWhitespace(srcStr.charAt(i + tokLenArr[j]))
2469                                ||  extraDelimiterTest.test(srcStr.charAt(i + tokLenArr[j])))
2470                        )
2471                            switch (booleanOperation)
2472                            {
2473                                case AND    :   tokLenArr[j] = -1;
2474                                                if (--count == 0)   return true;
2475                                                else                break;
2476                                case XOR    :   tokLenArr[j] = -1;
2477                                                if (++count > 1)    return false;
2478                                                else                break;
2479                                case OR     :   return true;
2480                                case NAND   :   return false;
2481                                default     :   throw new IllegalArgumentException
2482                                                (CONTAINS_EX.replace("BOOL", "" + booleanOperation));
2483                            }
2484
2485        switch(booleanOperation)
2486        {
2487            case AND    : return false;
2488            case OR     : return false;
2489            case XOR    : return count == 1;
2490            case NAND   : return true;
2491            default     : throw new IllegalArgumentException
2492                            (CONTAINS_EX.replace("BOOL", "" + booleanOperation));
2493        }
2494    }
2495
2496    /**
2497     * Implementing a 'contains' is more efficient by performing only one loop iteration.
2498     * Therefore, the methods that implement some variant of the {@code String.contains} method
2499     * will use this general-purpose {@code contains}-testing method.
2500     * @param ignoresCase This is used to signify whether to ignore case when performing the
2501     * {@code String}-comparison operations.
2502     * @param booleanOperation This is designed to take one of four values.  This method will
2503     * throw an exception if it does not.
2504     * @param srcStr Any non-null instance of {@code java.lang.String}
2505     * @param extraDelimiterTest <EMBED CLASS='external-html' DATA-FILE-ID='XTRADELIM'>
2506     * @param tokens This is one (or many) java {@code String's}, each of which shall be
2507     * checked whether it is contained by {@code 'srcStr'}.
2508     * @return The appropriate response based on the inputs for boolean logic.
2509     */
2510    protected static boolean CONTAINS(
2511        boolean ignoresCase, byte booleanOperation, String srcStr, 
2512        Predicate<Character> extraDelimiterTest, String[] tokens
2513    )
2514    {
2515        int     count       = (booleanOperation == XOR) ? 0 : tokens.length;
2516        int     len         = srcStr.length();
2517        int[]   tokLenArr   = new int[tokens.length];
2518        
2519        for (int i=0; i < tokLenArr.length; i++) tokLenArr[i] = tokens[i].length();
2520
2521        for (int i=0; i < len; i++)
2522            for (int j=0; j < tokens.length; j++)
2523                if (tokLenArr[j] != -1)
2524                    if (srcStr.regionMatches(ignoresCase, i, tokens[j], 0, tokLenArr[j]))
2525                        if (    (   (i==0)
2526                                ||  Character.isWhitespace(srcStr.charAt(i-1))
2527                                ||  extraDelimiterTest.test(srcStr.charAt(i-1)))
2528                            &&  (   ((i+tokLenArr[j]) == len)
2529                                ||  Character.isWhitespace(srcStr.charAt(i+tokLenArr[j]))
2530                                ||  extraDelimiterTest.test(srcStr.charAt(i+tokLenArr[j])))
2531                        )
2532                            switch (booleanOperation)
2533                            {
2534                                case AND    :   tokLenArr[j] = -1;
2535                                                if (--count == 0)   return true;
2536                                                else                break;
2537                                case XOR    :   tokLenArr[j] = -1;
2538                                                if (++count > 1)    return false;
2539                                                else                break;
2540                                case OR     :   return true;
2541                                case NAND   :   return false;
2542                                default     :   throw new IllegalArgumentException
2543                                                (CONTAINS_EX.replace("BOOL", "" + booleanOperation));
2544                            }
2545
2546        switch(booleanOperation)
2547        {
2548            case AND    : return false;
2549            case OR     : return false;
2550            case XOR    : return count == 1;
2551            case NAND   : return true;
2552            default     : throw new IllegalArgumentException
2553                            (CONTAINS_EX.replace("BOOL", "" + booleanOperation));
2554        }
2555    }
2556
2557}