Java 查找字符串中出现的多个单词,并存储相应的起始索引

Java 查找字符串中出现的多个单词,并存储相应的起始索引,java,string,split,find-occurrences,Java,String,Split,Find Occurrences,背景 我有一个文本字符串和一个哈希集,其中包含我要查找的单词 给定 ` 尝试 //create hashmap for(int i = 0; i<testDoc.length; i++){ if(setW.contains(testDoc[i])) { doc.indexOf(testDoc[i]); //add string and its index to hashmap } //创建hashmap 对于(int i=0;i有一个重载版本

背景

我有一个文本字符串和一个哈希集,其中包含我要查找的单词

给定

` 尝试

//create hashmap
for(int i = 0; i<testDoc.length; i++){
    if(setW.contains(testDoc[i])) {
        doc.indexOf(testDoc[i]);
       //add string and its index to hashmap
    }
//创建hashmap

对于(int i=0;i有一个重载版本,它以索引开始搜索。您可以使用它重复搜索同一字符串,直到到达末尾


请注意,您可以删除对
contains()
的测试,这样就不会搜索字符串两次。

将单词列表转换为正则表达式,并让正则表达式为您执行搜索

例如,您的3个单词将是这样的正则表达式:

和| of | one
当然,您不需要部分单词,因此您需要添加单词边界检查:

\b(和| of | one)\b
无需捕获单词(再次),因为整个匹配项都是单词,所以请使用非捕获组。您还可以轻松地使单词搜索不区分大小写

虽然纯单词(所有字母)永远不会有问题,但最好使用
Pattern.quote()
引用单词来保护正则表达式

范例

输出

one-->0
of-->4
and-->15
and-->24
one-->28
of-->32
1-->0
共-->4个
和-->15
和-->24
一-->28
第-->32页

如果您想稍微压缩(模糊)代码,可以在Java 9+中将其编写为一条语句:

Pattern.compile(Stream.of(words).collect(joining("|", "(?i)\\b(?:", ")\\b"))).matcher(doc).results().forEach(r -> System.out.println(r.group() + "-->" + r.start()));

输出是一样的。

如果你想进行较少的迭代,还有另一种解决方案,这段代码只遍历字符串一次。我想一个字符一个字符地访问一个字符串。我用一个StringBuilder附加每个字符,并检查当你得到空白时,只需将该字符串附加到最终答案列表中,并添加输入德克斯也是。 我在下面描述了我的方法,我认为它只是访问每个字符一次,这个代码的时间复杂度是O(n)


愚蠢的我!我应该知道得更清楚。这对我来说很有用!我可以在6分钟内接受你的答案。@Dinero注意,我在这里提出的建议需要对你的代码进行比我最初想象的更多的修改。你应该迭代
testDoc
中的单词,而不是迭代
setW
中的单词,然后在
doc
中搜索它们>。这样就完全不需要
testDoc
。@Dinero有另一种方法可以使用
testDoc
并在迭代时计算索引。
testDoc
中的第一个单词从索引0开始。下一个单词从索引
testDoc[0]开始。length()+1
等等。这样就不需要调用
indexOf()
完全同意。同意你的第二条评论,你建议我在setW中迭代单词的第一条评论意味着我必须进行多次迭代。在后一种情况下,我可以在一次扫描中找出所有出现的单词和索引。@Dinero无论哪种方式,我描述的两种算法都需要多次迭代。我的意思是你ve迭代
setW
中的单词和
doc
中的单词。
String doc = "one of the car and bike and one of those";
String[] words = { "and", "of", "one" };

// Build regex
StringJoiner joiner = new StringJoiner("|", "\\b(?:", ")\\b");
for (String word : words)
    joiner.add(Pattern.quote(word));
String regex = joiner.toString();

// Find words
for (Matcher m = Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(doc); m.find(); )
    System.out.println(m.group() + "-->" + m.start());
Pattern.compile(Stream.of(words).collect(joining("|", "(?i)\\b(?:", ")\\b"))).matcher(doc).results().forEach(r -> System.out.println(r.group() + "-->" + r.start()));
StringBuilder sb=new StringBuilder();
    ArrayList<String> answer=new ArrayList<>();
    ArrayList<Integer> index=new ArrayList<>();
    HashSet<String> setW = new HashSet<>();
    setW.add("and");
    setW.add("of");
    setW.add("one");
    index.add(0);
    String doc = "one of the car and bike and one of those";
    for(int i=0;i<doc.length();i++){
        if(i==doc.length() || doc.charAt(i)==' '){
            index.add(i+1);
            answer.add(sb.toString());
            sb=new StringBuilder();
            i++;
        }
        sb.append(doc.charAt(i));
        if(i==doc.length()-1){
            if(setW.contains(sb.toString())){
                answer.add(sb.toString());
            };
        }
    }
    for(int i=0;i<answer.size();i++){
        if(setW.contains(answer.get(i))){
            System.out.println(answer.get(i)+"-->"+index.get(i));
        }
    }
one-->0
of-->4
and-->15
and-->24
one-->28
of-->32