Example usage for java.lang CharSequence charAt

List of usage examples for java.lang CharSequence charAt

Introduction

In this page you can find the example usage for java.lang CharSequence charAt.

Prototype

char charAt(int index);

Source Link

Document

Returns the char value at the specified index.

Usage

From source file:bfile.util.StringUtils.java

/**
 * <p>Checks that the CharSequence does not contain certain characters.</p>
 *
 * <p>A {@code null} CharSequence will return {@code true}.
 * A {@code null} invalid character array will return {@code true}.
 * An empty CharSequence (length()=0) always returns true.</p>
 *
 * <pre>/*www .  ja v  a 2  s. co m*/
 * StringUtils.containsNone(null, *)       = true
 * StringUtils.containsNone(*, null)       = true
 * StringUtils.containsNone("", *)         = true
 * StringUtils.containsNone("ab", '')      = true
 * StringUtils.containsNone("abab", 'xyz') = true
 * StringUtils.containsNone("ab1", 'xyz')  = true
 * StringUtils.containsNone("abz", 'xyz')  = false
 * </pre>
 *
 * @param cs  the CharSequence to check, may be null
 * @param searchChars  an array of invalid chars, may be null
 * @return true if it contains none of the invalid chars, or is null
 * @since 2.0
 * @since 3.0 Changed signature from containsNone(String, char[]) to containsNone(CharSequence, char...)
 */
public static boolean containsNone(final CharSequence cs, final char... searchChars) {
    if (cs == null || searchChars == null) {
        return true;
    }
    final int csLen = cs.length();
    final int csLast = csLen - 1;
    final int searchLen = searchChars.length;
    final int searchLast = searchLen - 1;
    for (int i = 0; i < csLen; i++) {
        final char ch = cs.charAt(i);
        for (int j = 0; j < searchLen; j++) {
            if (searchChars[j] == ch) {
                if (Character.isHighSurrogate(ch)) {
                    if (j == searchLast) {
                        // missing low surrogate, fine, like String.indexOf(String)
                        return false;
                    }
                    if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
                        return false;
                    }
                } else {
                    // ch is in the Basic Multilingual Plane
                    return false;
                }
            }
        }
    }
    return true;
}

From source file:bfile.util.StringUtils.java

/**
 * <p>Search a CharSequence to find the first index of any
 * character in the given set of characters.</p>
 *
 * <p>A {@code null} String will return {@code -1}.
 * A {@code null} or zero length search array will return {@code -1}.</p>
 *
 * <pre>//from w w  w  .j  a  v a  2  s. c  o m
 * StringUtils.indexOfAny(null, *)                = -1
 * StringUtils.indexOfAny("", *)                  = -1
 * StringUtils.indexOfAny(*, null)                = -1
 * StringUtils.indexOfAny(*, [])                  = -1
 * StringUtils.indexOfAny("zzabyycdxx",['z','a']) = 0
 * StringUtils.indexOfAny("zzabyycdxx",['b','y']) = 3
 * StringUtils.indexOfAny("aba", ['z'])           = -1
 * </pre>
 *
 * @param cs  the CharSequence to check, may be null
 * @param searchChars  the chars to search for, may be null
 * @return the index of any of the chars, -1 if no match or null input
 * @since 2.0
 * @since 3.0 Changed signature from indexOfAny(String, char[]) to indexOfAny(CharSequence, char...)
 */
public static int indexOfAny(final CharSequence cs, final char... searchChars) {
    if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
        return INDEX_NOT_FOUND;
    }
    final int csLen = cs.length();
    final int csLast = csLen - 1;
    final int searchLen = searchChars.length;
    final int searchLast = searchLen - 1;
    for (int i = 0; i < csLen; i++) {
        final char ch = cs.charAt(i);
        for (int j = 0; j < searchLen; j++) {
            if (searchChars[j] == ch) {
                if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
                    // ch is a supplementary character
                    if (searchChars[j + 1] == cs.charAt(i + 1)) {
                        return i;
                    }
                } else {
                    return i;
                }
            }
        }
    }
    return INDEX_NOT_FOUND;
}

From source file:bfile.util.StringUtils.java

/**
 * <p>Searches a CharSequence to find the first index of any
 * character not in the given set of characters.</p>
 *
 * <p>A {@code null} CharSequence will return {@code -1}.
 * A {@code null} or zero length search array will return {@code -1}.</p>
 *
 * <pre>/*from  w  w w  .  ja  v a2s .c om*/
 * StringUtils.indexOfAnyBut(null, *)                              = -1
 * StringUtils.indexOfAnyBut("", *)                                = -1
 * StringUtils.indexOfAnyBut(*, null)                              = -1
 * StringUtils.indexOfAnyBut(*, [])                                = -1
 * StringUtils.indexOfAnyBut("zzabyycdxx", new char[] {'z', 'a'} ) = 3
 * StringUtils.indexOfAnyBut("aba", new char[] {'z'} )             = 0
 * StringUtils.indexOfAnyBut("aba", new char[] {'a', 'b'} )        = -1
 * </pre>
 *
 * @param cs  the CharSequence to check, may be null
 * @param searchChars  the chars to search for, may be null
 * @return the index of any of the chars, -1 if no match or null input
 * @since 2.0
 * @since 3.0 Changed signature from indexOfAnyBut(String, char[]) to indexOfAnyBut(CharSequence, char...)
 */
public static int indexOfAnyBut(final CharSequence cs, final char... searchChars) {
    if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
        return INDEX_NOT_FOUND;
    }
    final int csLen = cs.length();
    final int csLast = csLen - 1;
    final int searchLen = searchChars.length;
    final int searchLast = searchLen - 1;
    outer: for (int i = 0; i < csLen; i++) {
        final char ch = cs.charAt(i);
        for (int j = 0; j < searchLen; j++) {
            if (searchChars[j] == ch) {
                if (i < csLast && j < searchLast && Character.isHighSurrogate(ch)) {
                    if (searchChars[j + 1] == cs.charAt(i + 1)) {
                        continue outer;
                    }
                } else {
                    continue outer;
                }
            }
        }
        return i;
    }
    return INDEX_NOT_FOUND;
}

From source file:bfile.util.StringUtils.java

/**
 * <p>Checks if the CharSequence contains any character in the given
 * set of characters.</p>//w  ww.  j  a  va2 s .c  o m
 *
 * <p>A {@code null} CharSequence will return {@code false}.
 * A {@code null} or zero length search array will return {@code false}.</p>
 *
 * <pre>
 * StringUtils.containsAny(null, *)                = false
 * StringUtils.containsAny("", *)                  = false
 * StringUtils.containsAny(*, null)                = false
 * StringUtils.containsAny(*, [])                  = false
 * StringUtils.containsAny("zzabyycdxx",['z','a']) = true
 * StringUtils.containsAny("zzabyycdxx",['b','y']) = true
 * StringUtils.containsAny("zzabyycdxx",['z','y']) = true
 * StringUtils.containsAny("aba", ['z'])           = false
 * </pre>
 *
 * @param cs  the CharSequence to check, may be null
 * @param searchChars  the chars to search for, may be null
 * @return the {@code true} if any of the chars are found,
 * {@code false} if no match or null input
 * @since 2.4
 * @since 3.0 Changed signature from containsAny(String, char[]) to containsAny(CharSequence, char...)
 */
public static boolean containsAny(final CharSequence cs, final char... searchChars) {
    if (isEmpty(cs) || ArrayUtils.isEmpty(searchChars)) {
        return false;
    }
    final int csLength = cs.length();
    final int searchLength = searchChars.length;
    final int csLast = csLength - 1;
    final int searchLast = searchLength - 1;
    for (int i = 0; i < csLength; i++) {
        final char ch = cs.charAt(i);
        for (int j = 0; j < searchLength; j++) {
            if (searchChars[j] == ch) {
                if (Character.isHighSurrogate(ch)) {
                    if (j == searchLast) {
                        // missing low surrogate, fine, like String.indexOf(String)
                        return true;
                    }
                    if (i < csLast && searchChars[j + 1] == cs.charAt(i + 1)) {
                        return true;
                    }
                } else {
                    // ch is in the Basic Multilingual Plane
                    return true;
                }
            }
        }
    }
    return false;
}

From source file:com.sjdf.platform.xss.StringUtils.java

/**
 * <p>/*w  w w . ja  va  2 s. c o  m*/
 * Find the Levenshtein distance between two Strings.
 * </p>
 * <p/>
 * <p>
 * This is the number of changes needed to change one String into another,
 * where each change is a single character modification (deletion, insertion
 * or substitution).
 * </p>
 * <p/>
 * <p>
 * The previous implementation of the Levenshtein distance algorithm was
 * from <a
 * href="http://www.merriampark.com/ld.htm">http://www.merriampark.com
 * /ld.htm</a>
 * </p>
 * <p/>
 * <p>
 * Chas Emerick has written an implementation in Java, which avoids an
 * OutOfMemoryError which can occur when my Java implementation is used with
 * very large strings.<br>
 * This implementation of the Levenshtein distance algorithm is from <a
 * href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/
 * ldjava.htm</a>
 * </p>
 * <p/>
 * <pre>
 * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
 * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
 * StringUtils.getLevenshteinDistance("","")               = 0
 * StringUtils.getLevenshteinDistance("","a")              = 1
 * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
 * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
 * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
 * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
 * </pre>
 *
 * @param ss the first String, must not be null
 * @param tt the second String, must not be null
 * @return result distance
 * @throws IllegalArgumentException if either String input {@code null}
 * @since 3.0 Changed signature from getLevenshteinDistance(String, String)
 * to getLevenshteinDistance(CharSequence, CharSequence)
 */
public static int getLevenshteinDistance(CharSequence ss, CharSequence tt) {
    CharSequence s = ss, t = tt;
    if (s == null || t == null) {
        throw new IllegalArgumentException("Strings must not be null");
    }

    /**
     * The difference between this impl. and the previous is that, rather
     * than creating and retaining a matrix of size s.length() + 1 by
     * t.length() + 1, we maintain two single-dimensional arrays of length
     * s.length() + 1. The first, d, is the 'current working' distance array
     * that maintains the newest distance cost counts as we iterate through
     * the characters of String s. Each time we increment the index of
     * String t we are comparing, d is copied to p, the second int[]. Doing
     * so allows us to retain the previous cost counts as required by the
     * algorithm (taking the minimum of the cost count to the left, up one,
     * and diagonally up and to the left of the current cost count being
     * calculated). (Note that the arrays aren't really copied anymore, just
     * switched...this is clearly much better than cloning an array or doing
     * a System.arraycopy() each time through the outer loop.)
     *
     * Effectively, the difference between the two implementations is this
     * one does not cause an out of memory condition when calculating the LD
     * over two very large strings.
     */

    int n = s.length();
    int m = t.length();

    if (n == 0) {
        return m;
    } else if (m == 0) {
        return n;
    }

    if (n > m) {
        // swap the input strings to consume less memory
        CharSequence tmp = s;
        s = t;
        t = tmp;
        n = m;
        m = t.length();
    }

    int[] p = new int[n + 1];
    int[] d = new int[n + 1];
    int[] pd;
    // indexes into strings s and t
    int i;
    int j;

    char tj;

    int cost;

    for (i = 0; i <= n; i++) {
        p[i] = i;
    }

    for (j = 1; j <= m; j++) {
        tj = t.charAt(j - 1);
        d[0] = j;

        for (i = 1; i <= n; i++) {
            cost = s.charAt(i - 1) == tj ? 0 : 1;
            // minimum of cell to the left+1, to the top+1, diagonally left
            // and up +cost
            d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
        }

        // copy current distance counts to 'previous row' distance counts
        pd = p;
        p = d;
        d = pd;
    }

    // our last action in the above loop was to switch d and p, so p now
    // actually has the most recent cost counts
    return p[n];
}

From source file:bfile.util.StringUtils.java

private static int[] matches(final CharSequence first, final CharSequence second) {
    CharSequence max, min;
    if (first.length() > second.length()) {
        max = first;/*from   w  w w.j  av  a  2s  .  c  o m*/
        min = second;
    } else {
        max = second;
        min = first;
    }
    final int range = Math.max(max.length() / 2 - 1, 0);
    final int[] matchIndexes = new int[min.length()];
    Arrays.fill(matchIndexes, -1);
    final boolean[] matchFlags = new boolean[max.length()];
    int matches = 0;
    for (int mi = 0; mi < min.length(); mi++) {
        final char c1 = min.charAt(mi);
        for (int xi = Math.max(mi - range, 0), xn = Math.min(mi + range + 1, max.length()); xi < xn; xi++) {
            if (!matchFlags[xi] && c1 == max.charAt(xi)) {
                matchIndexes[mi] = xi;
                matchFlags[xi] = true;
                matches++;
                break;
            }
        }
    }
    final char[] ms1 = new char[matches];
    final char[] ms2 = new char[matches];
    for (int i = 0, si = 0; i < min.length(); i++) {
        if (matchIndexes[i] != -1) {
            ms1[si] = min.charAt(i);
            si++;
        }
    }
    for (int i = 0, si = 0; i < max.length(); i++) {
        if (matchFlags[i]) {
            ms2[si] = max.charAt(i);
            si++;
        }
    }
    int transpositions = 0;
    for (int mi = 0; mi < ms1.length; mi++) {
        if (ms1[mi] != ms2[mi]) {
            transpositions++;
        }
    }
    int prefix = 0;
    for (int mi = 0; mi < min.length(); mi++) {
        if (first.charAt(mi) == second.charAt(mi)) {
            prefix++;
        } else {
            break;
        }
    }
    return new int[] { matches, transpositions / 2, prefix, max.length() };
}

From source file:bfile.util.StringUtils.java

/**
 * <p>Find the Levenshtein distance between two Strings.</p>
 *
 * <p>This is the number of changes needed to change one String into
 * another, where each change is a single character modification (deletion,
 * insertion or substitution).</p>
 *
 * <p>The implementation uses a single-dimensional array of length s.length() + 1. See
 * <a href="http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html">
 * http://blog.softwx.net/2014/12/optimizing-levenshtein-algorithm-in-c.html</a> for details.</p>
 *
 * <pre>/*from w  w  w.  ja va2 s.  co  m*/
 * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
 * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
 * StringUtils.getLevenshteinDistance("","")               = 0
 * StringUtils.getLevenshteinDistance("","a")              = 1
 * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
 * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
 * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
 * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
 * </pre>
 *
 * @param s  the first String, must not be null
 * @param t  the second String, must not be null
 * @return result distance
 * @throws IllegalArgumentException if either String input {@code null}
 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
 * getLevenshteinDistance(CharSequence, CharSequence)
 */
public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    if (s == null || t == null) {
        throw new IllegalArgumentException("Strings must not be null");
    }

    int n = s.length();
    int m = t.length();

    if (n == 0) {
        return m;
    } else if (m == 0) {
        return n;
    }

    if (n > m) {
        // swap the input strings to consume less memory
        final CharSequence tmp = s;
        s = t;
        t = tmp;
        n = m;
        m = t.length();
    }

    final int p[] = new int[n + 1];
    // indexes into strings s and t
    int i; // iterates through s
    int j; // iterates through t
    int upper_left;
    int upper;

    char t_j; // jth character of t
    int cost;

    for (i = 0; i <= n; i++) {
        p[i] = i;
    }

    for (j = 1; j <= m; j++) {
        upper_left = p[0];
        t_j = t.charAt(j - 1);
        p[0] = j;

        for (i = 1; i <= n; i++) {
            upper = p[i];
            cost = s.charAt(i - 1) == t_j ? 0 : 1;
            // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
            p[i] = Math.min(Math.min(p[i - 1] + 1, p[i] + 1), upper_left + cost);
            upper_left = upper;
        }
    }

    return p[n];
}

From source file:com.rdm.common.util.StringUtils.java

/**
 * <p>Find the Levenshtein distance between two Strings.</p>
 *
 * <p>This is the number of changes needed to change one String into
 * another, where each change is a single character modification (deletion,
 * insertion or substitution).</p>
 *
 * <p>The previous implementation of the Levenshtein distance algorithm
 * was from <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
 *
 * <p>Chas Emerick has written an implementation in Java, which avoids an OutOfMemoryError
 * which can occur when my Java implementation is used with very large strings.<br>
 * This implementation of the Levenshtein distance algorithm
 * is from <a href="http://www.merriampark.com/ldjava.htm">http://www.merriampark.com/ldjava.htm</a></p>
 *
 * <pre>//from w  w w  .j  a  v  a  2s. c  o m
 * StringUtils.getLevenshteinDistance(null, *)             = IllegalArgumentException
 * StringUtils.getLevenshteinDistance(*, null)             = IllegalArgumentException
 * StringUtils.getLevenshteinDistance("","")               = 0
 * StringUtils.getLevenshteinDistance("","a")              = 1
 * StringUtils.getLevenshteinDistance("aaapppp", "")       = 7
 * StringUtils.getLevenshteinDistance("frog", "fog")       = 1
 * StringUtils.getLevenshteinDistance("fly", "ant")        = 3
 * StringUtils.getLevenshteinDistance("elephant", "hippo") = 7
 * StringUtils.getLevenshteinDistance("hippo", "elephant") = 7
 * StringUtils.getLevenshteinDistance("hippo", "zzzzzzzz") = 8
 * StringUtils.getLevenshteinDistance("hello", "hallo")    = 1
 * </pre>
 *
 * @param s  the first String, must not be null
 * @param t  the second String, must not be null
 * @return result distance
 * @throws IllegalArgumentException if either String input {@code null}
 * @since 3.0 Changed signature from getLevenshteinDistance(String, String) to
 * getLevenshteinDistance(CharSequence, CharSequence)
 */
public static int getLevenshteinDistance(CharSequence s, CharSequence t) {
    if (s == null || t == null) {
        throw new IllegalArgumentException("Strings must not be null");
    }

    /*
       The difference between this impl. and the previous is that, rather
       than creating and retaining a matrix of size s.length() + 1 by t.length() + 1,
       we maintain two single-dimensional arrays of length s.length() + 1.  The first, d,
       is the 'current working' distance array that maintains the newest distance cost
       counts as we iterate through the characters of String s.  Each time we increment
       the index of String t we are comparing, d is copied to p, the second int[].  Doing so
       allows us to retain the previous cost counts as required by the algorithm (taking
       the minimum of the cost count to the left, up one, and diagonally up and to the left
       of the current cost count being calculated).  (Note that the arrays aren't really
       copied anymore, just switched...this is clearly much better than cloning an array
       or doing a System.arraycopy() each time  through the outer loop.)
            
       Effectively, the difference between the two implementations is this one does not
       cause an out of memory condition when calculating the LD over two very large strings.
     */

    int n = s.length(); // length of s
    int m = t.length(); // length of t

    if (n == 0) {
        return m;
    } else if (m == 0) {
        return n;
    }

    if (n > m) {
        // swap the input strings to consume less memory
        final CharSequence tmp = s;
        s = t;
        t = tmp;
        n = m;
        m = t.length();
    }

    int p[] = new int[n + 1]; //'previous' cost array, horizontally
    int d[] = new int[n + 1]; // cost array, horizontally
    int _d[]; //placeholder to assist in swapping p and d

    // indexes into strings s and t
    int i; // iterates through s
    int j; // iterates through t

    char t_j; // jth character of t

    int cost; // cost

    for (i = 0; i <= n; i++) {
        p[i] = i;
    }

    for (j = 1; j <= m; j++) {
        t_j = t.charAt(j - 1);
        d[0] = j;

        for (i = 1; i <= n; i++) {
            cost = s.charAt(i - 1) == t_j ? 0 : 1;
            // minimum of cell to the left+1, to the top+1, diagonally left and up +cost
            d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost);
        }

        // copy current distance counts to 'previous row' distance counts
        _d = p;
        p = d;
        d = _d;
    }

    // our last action in the above loop was to switch d and p, so p now
    // actually has the most recent cost counts
    return p[n];
}

From source file:org.jan.common.utils.lang.StringUtils.java

/**
 * <p>Find the Levenshtein distance between two Strings if it's less than or equal to a given
 * threshold.</p>//from  w  w w.j a  v a2 s . c  o m
 *
 * <p>This is the number of changes needed to change one String into
 * another, where each change is a single character modification (deletion,
 * insertion or substitution).</p>
 *
 * <p>This implementation follows from Algorithms on Strings, Trees and Sequences by Dan Gusfield
 * and Chas Emerick's implementation of the Levenshtein distance algorithm from
 * <a href="http://www.merriampark.com/ld.htm">http://www.merriampark.com/ld.htm</a></p>
 *
 * <pre>
 * StringUtils.getLevenshteinDistance(null, *, *)             = IllegalArgumentException
 * StringUtils.getLevenshteinDistance(*, null, *)             = IllegalArgumentException
 * StringUtils.getLevenshteinDistance(*, *, -1)               = IllegalArgumentException
 * StringUtils.getLevenshteinDistance("","", 0)               = 0
 * StringUtils.getLevenshteinDistance("aaapppp", "", 8)       = 7
 * StringUtils.getLevenshteinDistance("aaapppp", "", 7)       = 7
 * StringUtils.getLevenshteinDistance("aaapppp", "", 6))      = -1
 * StringUtils.getLevenshteinDistance("elephant", "hippo", 7) = 7
 * StringUtils.getLevenshteinDistance("elephant", "hippo", 6) = -1
 * StringUtils.getLevenshteinDistance("hippo", "elephant", 7) = 7
 * StringUtils.getLevenshteinDistance("hippo", "elephant", 6) = -1
 * </pre>
 *
 * @param s  the first String, must not be null
 * @param t  the second String, must not be null
 * @param threshold the target threshold, must not be negative
 * @return result distance, or {@code -1} if the distance would be greater than the threshold
 * @throws IllegalArgumentException if either String input {@code null} or negative threshold
 */
public static int getLevenshteinDistance(CharSequence s, CharSequence t, int threshold) {
    if (s == null || t == null) {
        throw new IllegalArgumentException("Strings must not be null");
    }
    if (threshold < 0) {
        throw new IllegalArgumentException("Threshold must not be negative");
    }

    /*
    This implementation only computes the distance if it's less than or equal to the
    threshold value, returning -1 if it's greater.  The advantage is performance: unbounded
    distance is O(nm), but a bound of k allows us to reduce it to O(km) time by only
    computing a diagonal stripe of width 2k + 1 of the cost table.
    It is also possible to use this to compute the unbounded Levenshtein distance by starting
    the threshold at 1 and doubling each time until the distance is found; this is O(dm), where
    d is the distance.
            
    One subtlety comes from needing to ignore entries on the border of our stripe
    eg.
    p[] = |#|#|#|*
    d[] =  *|#|#|#|
    We must ignore the entry to the left of the leftmost member
    We must ignore the entry above the rightmost member
            
    Another subtlety comes from our stripe running off the matrix if the strings aren't
    of the same size.  Since string s is always swapped to be the shorter of the two,
    the stripe will always run off to the upper right instead of the lower left of the matrix.
            
    As a concrete example, suppose s is of length 5, t is of length 7, and our threshold is 1.
    In this case we're going to walk a stripe of length 3.  The matrix would look like so:
            
       1 2 3 4 5
    1 |#|#| | | |
    2 |#|#|#| | |
    3 | |#|#|#| |
    4 | | |#|#|#|
    5 | | | |#|#|
    6 | | | | |#|
    7 | | | | | |
            
    Note how the stripe leads off the table as there is no possible way to turn a string of length 5
    into one of length 7 in edit distance of 1.
            
    Additionally, this implementation decreases memory usage by using two
    single-dimensional arrays and swapping them back and forth instead of allocating
    an entire n by m matrix.  This requires a few minor changes, such as immediately returning
    when it's detected that the stripe has run off the matrix and initially filling the arrays with
    large values so that entries we don't compute are ignored.
            
    See Algorithms on Strings, Trees and Sequences by Dan Gusfield for some discussion.
     */

    int n = s.length(); // length of s
    int m = t.length(); // length of t

    // if one string is empty, the edit distance is necessarily the length of the other
    if (n == 0) {
        return m <= threshold ? m : -1;
    } else if (m == 0) {
        return n <= threshold ? n : -1;
    }

    if (n > m) {
        // swap the two strings to consume less memory
        CharSequence tmp = s;
        s = t;
        t = tmp;
        n = m;
        m = t.length();
    }

    int p[] = new int[n + 1]; // 'previous' cost array, horizontally
    int d[] = new int[n + 1]; // cost array, horizontally
    int _d[]; // placeholder to assist in swapping p and d

    // fill in starting table values
    int boundary = Math.min(n, threshold) + 1;
    for (int i = 0; i < boundary; i++) {
        p[i] = i;
    }
    // these fills ensure that the value above the rightmost entry of our
    // stripe will be ignored in following loop iterations
    Arrays.fill(p, boundary, p.length, Integer.MAX_VALUE);
    Arrays.fill(d, Integer.MAX_VALUE);

    // iterates through t
    for (int j = 1; j <= m; j++) {
        char t_j = t.charAt(j - 1); // jth character of t
        d[0] = j;

        // compute stripe indices, constrain to array size
        int min = Math.max(1, j - threshold);
        int max = Math.min(n, j + threshold);

        // the stripe may lead off of the table if s and t are of different sizes
        if (min > max) {
            return -1;
        }

        // ignore entry left of leftmost
        if (min > 1) {
            d[min - 1] = Integer.MAX_VALUE;
        }

        // iterates through [min, max] in s
        for (int i = min; i <= max; i++) {
            if (s.charAt(i - 1) == t_j) {
                // diagonally left and up
                d[i] = p[i - 1];
            } else {
                // 1 + minimum of cell to the left, to the top, diagonally left and up
                d[i] = 1 + Math.min(Math.min(d[i - 1], p[i]), p[i - 1]);
            }
        }

        // copy current distance counts to 'previous row' distance counts
        _d = p;
        p = d;
        d = _d;
    }

    // if p[n] is greater than the threshold, there's no guarantee on it being the correct
    // distance
    if (p[n] <= threshold) {
        return p[n];
    } else {
        return -1;
    }
}