首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >查找字符串中出现的多个单词,并存储相应的起始索引

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

Stack Overflow用户
提问于 2019-06-06 07:14:40
回答 3查看 1.3K关注 0票数 1

背景

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

给定的

代码语言:javascript
复制
String doc = "one of the car and bike and one of those";
String [] testDoc = doc.split("\\s+");
HashSet<String> setW = new HashSet<>();
setW.add("and");
setW.add("of");
setW.add("one");

目标

我们的目标是扫描字符串,每次我们遇到散列集中的单词时,我们都要存储该单词和起始索引的位置。

在上面的情况下,我们应该能够存储以下内容

代码语言:javascript
复制
one-->0 

of-->4 

and-->15 

and-->24, 

one-->28, 

of-->32

`尝试

代码语言:javascript
复制
//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
    }

到目前为止,这就是我所想到的,唯一的问题是indexOf方法只查看第一次出现的单词,所以我不确定该怎么做。如果我在扫描完每个单词后不断修剪字符串,那么我将不会获得原始字符串中单词的索引位置。

我想在这里提供一些意见。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-06-06 07:19:17

有一个重载版本的indexOf(),它接受一个索引来开始搜索。您可以使用它重复搜索相同的字符串,直到到达末尾。

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

票数 3
EN

Stack Overflow用户

发布于 2019-06-06 07:53:46

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

例如,你的3个单词将是如下所示的正则表达式:

代码语言:javascript
复制
and|of|one

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

代码语言:javascript
复制
\b(and|of|one)\b

不需要(再次)捕获单词,因为整个匹配都是单词,所以使用非捕获组。您还可以轻松地使单词搜索不区分大小写。

尽管纯单词(全是字母)永远不会有问题,但通过使用Pattern.quote()引用单词来保护正则表达式是一个好主意。

示例

代码语言:javascript
复制
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());

输出

代码语言:javascript
复制
one-->0
of-->4
and-->15
and-->24
one-->28
of-->32

如果您想对代码进行一点压缩(模糊处理),您可以将其编写为Java 9+中的单个语句:

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

输出是相同的。

票数 0
EN

Stack Overflow用户

发布于 2019-06-08 01:27:15

如果你想减少迭代,还有另一个解决方案,这段代码遍历字符串一次。我想要一个字符一个字符地访问字符串。我使用了一个StringBuilder来添加每个字符,当您获得空格时,只需将该字符串添加到最终的答案列表中,并添加索引。我已经将我的方法描述如下,我认为它只访问每个字符一次,这段代码的时间复杂度是O(n)。

代码语言:javascript
复制
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));
        }
    }

我基于这个想法得到了预期的输出,提交这个问题的答案背后的原因是为了获得另一个可能的解决方案。(在回答HashSet时,我们将得到setW中存在的每个单词的索引,所以如果您不想这样做,可以使用一个if(!setW.contains(answer.get(i))条件将其删除。)

输出

代码语言:javascript
复制
one-->0
of-->4
and-->15
and-->24
one-->28
of-->32
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56469180

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档