如何迭代子字符串递增 1 个位置的大字符串?

How to iterate through large string with substrings incrementing by 1 position?

我有一个包含大量数字(数千个字符)的字符串:

String pi = "3.14159265358979323846264338327950288419716939937..."

我想遍历这个字符串,一次抓取 6 个字符,并检查它们是否与给定的字符串匹配:

String substring = "3.1415"

但是,在每个后续子字符串上,我想将原始字符串中的字符向右移动 1 个位置:

substring = ".14159"
substring = "141592"
substring = "415926"
substring = "159265"

等等等

最好的方法是什么?我考虑过 StringBuilder 的方法,但每次迭代都转换为 String 可能代价高昂。字符串的方法

substring(int beginIndex, int endIndex)

似乎接近我正在尝试做的事情,但我不知道这些索引是否可以通过算法递增。

I don't know if those indices can be incremented algorithmically.

这些是参数。它们是您为每次调用方法提供的值。

您可以根据变量、常量、表达式、用户输入或其他任何内容自由指定任何内容。在这种情况下,您可以保留一个或两个变量,将它们递增,然后将它们作为参数传递。

这是一个使用两个每次迭代都递增 1 的变量的示例:

class Main {
  public static void main(String[] args) {
    String pi = "3.14159265358979323846264338327950288419716939937...";
    for(int start=0, end=6; end <= pi.length(); start++, end++) {
      String substring = pi.substring(start, end);
      System.out.println(substring);
    }
  }
}

这是一种可以高效匹配值的算法。 可能比使用子字符串方法更有效,因为一旦值与提供的序列不匹配,它就会短路。

public static int containsSubstring(String wholeString, String findValue) {
    //Break values into arrays
    char[] wholeArray = wholeString.toCharArray();
    char[] findArray = findValue.toCharArray();

    //Use named outer loop for easy continuation to next character place
    outerLoop:
    for(int i = 0; i < wholeArray.length; i++) {
        //Remaining values aren't large enough to contain find values so stop looking
        if(i + findArray.length > wholeArray.length) {
            break;
        }

        //Loop through next couple digits to check for matching sequence
        for(int j = 0; j < findArray.length; j++) {
            //Breaks loop as soon as a values don't match
            if(wholeArray[i + j] != findArray[j]) {
                continue outerLoop;
            }
        }

        return i; //Or 'true' of you just care whether it's in there, and set the method return to boolean
    }

    return -1; //Or 'false'
}

或java8款

String pi = "3.14159265358979323846264338327950288419716939937...";
IntStream.range(0, pi.length() - 5)
        .mapToObj(i -> new StringBuffer(pi.substring(i, i + 6)))
        .forEach(System.out::println)
;

你有可能让它平行

String pi = "3.14159265358979323846264338327950288419716939937...";
IntStream.range(0, pi.length() - 5)
        .mapToObj(i -> new StringBuffer(pi.substring(i, i + 6)))
        .parallel()
        .forEach(System.out::println)
;    

说到性能,经典的for循环方法还是要快一点的;你应该做一些测试:

public class Main {

    static long firstTestTime;
    static long withStreamTime;

    static String pi = "3.141592653589793238462643383279502884197169399375105820974944592307816";

    public static void main(String[] args) {
        firstTest(pi);
        withStreams(pi);

        System.out.println("First Test: " + firstTestTime);
        System.out.println("With Streams: " + withStreamTime);
    }

    static void withStreams(String pi) {
        System.out.println("Starting stream test");
        long startTime = System.currentTimeMillis();

        IntStream.range(0, pi.length() - 5)
                .mapToObj(i -> new StringBuffer(pi.substring(i, i + 6)))
                //.parallel()
                .forEach(System.out::println)
        ;

        withStreamTime = System.currentTimeMillis() - startTime;
    }

    // By @that other guy
    static void firstTest(String pi) {
        System.out.println("Starting first test");
        long startTime = System.currentTimeMillis();

        for(int start=0, end=6; end <= pi.length(); start++, end++) {
            String substring = pi.substring(start, end);
            System.out.println(substring);
        }

        firstTestTime = System.currentTimeMillis() - startTime;
    }

}

尽量增加希腊圆周率的长度!