【问题标题】:What substring search algorithm is used by different JREs?不同的 JRE 使用什么子字符串搜索算法?
【发布时间】:2011-08-15 08:52:52
【问题描述】:

java.lang.String JavaDoc 没有提及默认的indexOf(String) 子字符串搜索算法。所以我的问题是——不同的 JRE 使用了哪些子字符串算法?

【问题讨论】:

  • 由于 Java 是跨平台的,因此偏离参考开源代码没有太大价值(处理原生代码/平台相关问题的类除外)
  • @Harry Joy,我明白了,默认的 Sun (Oracle) JRE 使用简单的实现,没有任何技巧 - 只是一步一步的比较。 JRockit 和其他的呢?
  • 可能他们使用相同。我不确定。
  • @Harry Joy 我也是,这就是问题所在。

标签: java algorithm string substring


【解决方案1】:

JDK 中的 src.zip 显示了实现:

/**
 * Code shared by String and StringBuffer to do searches. The
 * source is the character array being searched, and the target
 * is the string being searched for.
 *
 * @param   source       the characters being searched.
 * @param   sourceOffset offset of the source string.
 * @param   sourceCount  count of the source string.
 * @param   target       the characters being searched for.
 * @param   targetOffset offset of the target string.
 * @param   targetCount  count of the target string.
 * @param   fromIndex    the index to begin searching from.
 */
static int indexOf(char[] source, int sourceOffset, int sourceCount,
                   char[] target, int targetOffset, int targetCount,
                   int fromIndex) {
if (fromIndex >= sourceCount) {
        return (targetCount == 0 ? sourceCount : -1);
}
    if (fromIndex < 0) {
        fromIndex = 0;
    }
if (targetCount == 0) {
    return fromIndex;
}

    char first  = target[targetOffset];
    int max = sourceOffset + (sourceCount - targetCount);

    for (int i = sourceOffset + fromIndex; i <= max; i++) {
        /* Look for first character. */
        if (source[i] != first) {
            while (++i <= max && source[i] != first);
        }

        /* Found first character, now look at the rest of v2 */
        if (i <= max) {
            int j = i + 1;
            int end = j + targetCount - 1;
            for (int k = targetOffset + 1; j < end && source[j] ==
                     target[k]; j++, k++);

            if (j == end) {
                /* Found whole string. */
                return i - sourceOffset;
            }
        }
    }
    return -1;
}

【讨论】:

  • 那么其他 JRE(我的意思是,非标准的)呢?
  • @Frozen Spider 我不知道 :) 但是由于 JavaDoc 或 JLS 中没有提到任何限制,所以它可能是合理的。
  • 这就是我问这个问题的原因 :) 我自己有 Sun 的 JDK,所以我想知道其他实现。
【解决方案2】:

由于大多数时候 indexOf 用于合理的小字符串中的小子字符串,我相信除了假设使用像 Victor 所示的那样相当简单的算法之外,还可以使用。有更高级的算法可以更好地处理大字符串,但 AFAIK 这些算法对于相对较短的字符串都表现较差。

【讨论】:

  • @Frozen:要确定,您必须查看每个 JVM 运行时库的 API 源代码。 JVM 没有强制性的标准字符串搜索算法。
  • 好吧,如果我没有得到足够的答案,我会这样做。
  • @Frozen Spider:如果知道确切的实现细节对你来说真的那么重要,你不应该问。你应该自己去检查,因为依赖答案的准确性是愚蠢的。另请注意,实现可能会因版本而异。
【解决方案3】:

fwiw(如果这个 Q 是关于不同算法的性能)在适当的硬件上和足够新的 oracle jvm(6u21 及更高版本,详见bug report),String.indexOf 是通过相关的 SSE 4.2 实现的内在函数.. 请参阅intel reference doc 中的第 2.3 章

【讨论】:

    【解决方案4】:

    这是目前发现的:

    Oracle JDK 1.6/1.7、OpenJDK 6/7

    static int indexOf(char[] source, int sourceOffset, int sourceCount,
                       char[] target, int targetOffset, int targetCount,
                       int fromIndex) {
    if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
    }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
    if (targetCount == 0) {
        return fromIndex;
    }
    
        char first  = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);
    
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }
    
            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j] ==
                         target[k]; j++, k++);
    
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }
    

    IBM JDK 5.0

    public int indexOf(String subString, int start) {
        if (start < 0) start = 0;
        int subCount = subString.count;
        if (subCount > 0) {
            if (subCount + start > count) return -1;
            char[] target = subString.value;
            int subOffset = subString.offset;
            char firstChar = target[subOffset];
            int end = subOffset + subCount;
            while (true) {
                int i = indexOf(firstChar, start);
                if (i == -1 || subCount + i > count) return -1; // handles subCount > count || start >= count
                int o1 = offset + i, o2 = subOffset;
                while (++o2 < end && value[++o1] == target[o2]);
                if (o2 == end) return i;
                start = i + 1;
            }
        } else return start < count ? start : count;
    }
    

    Sabre SDK

      public int indexOf(String str, int fromIndex)
      {
        if (fromIndex < 0)
          fromIndex = 0;
        int limit = count - str.count;
        for ( ; fromIndex <= limit; fromIndex++)
          if (regionMatches(fromIndex, str, 0, str.count))
            return fromIndex;
        return -1;
      }
    

    请随时更新这篇文章。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-29
      • 1970-01-01
      • 2011-03-12
      • 2012-01-24
      • 1970-01-01
      相关资源
      最近更新 更多