【问题标题】:Find chars in string that are not between double qotes在字符串中查找不在双引号之间的字符
【发布时间】:2016-06-03 04:28:24
【问题描述】:

我想查找 (a) 特定字符的出现,但此要搜索的字符串不能在引号之间:

例子:

"this is \"my\" example string" 

如果您查找 char 'm',那么它应该只从“example”返回 'm' 的索引,因为另一个 ' 在双引号之间。

另一个例子:

"th\"i\"s \"is\" \"my\" example string"

我期待这样的事情:

public List<Integer> getOccurrenceStartIndexesThatAreNotBetweenQuotes(String snippet,String stringToFind);

一种“天真的”方式是:

  • 获取sn-p中stringToFind的所有起始索引

  • 获取sn-p中所有引号的索引

  • 取决于stringToFind的起始索引,因为你有引号的位置,你可以知道你是否在引号之间。

有没有更好的方法来做到这一点?

编辑:

我要检索什么?匹配的索引。

几件事:

  • 在字符串中可以有很多引用的内容来搜索:"th\"i\"s \"is\" \"my\" example string"

  • 在字符串中:"th\"i\"s \"is\" \"my\" 示例字符串"、"i"、"is" 和 "my" 在引号之间。

  • 不限于字母和数字,我们可以有';:()_-=+[]{}等...

【问题讨论】:

  • 如何删除引号中的所有内容以及引号字符,然后搜索是否只想查找出现的内容?
  • 一个蛮力选项是查找所有引号对的索引,m 的所有索引,然后排除那些会落在引号内的索引。
  • @TimBiegeleisen 这就是我在上一段中试图解释的内容。
  • 目前尚不清楚您打算如何处理符合条件的子字符串,但要考虑的其他选项是 java.util.regex 包或 java.io.StreamTokenizer 类。如果你愿意添加一个开源库,你也有org.apache.commons.lang3.text
  • 我只想找到不在双引号之间的字符串出现的索引。

标签: java string


【解决方案1】:

这里有一个解决方案:

算法

  1. 查找字符串中的所有“死区”区域(例如,由于在引号内而不受限制的区域)
  2. 查找字符串中包含相关搜索字符串的所有区域(代码中的hitZones)。
  3. 仅保留hitZones 中不包含在任何deadZones 中的区域。我会把这部分留给你:)

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FindStrings
{
    // Just a simple model class for regions
    static class Pair
    {
        int s = 0;
        int e = 0;

        public Pair (int s, int e)
        {
            this.s = s;
            this.e = e;
        }

        public String toString ()
        {
            return "[" + s + ", " + e + "]";
        }
    }

    public static void main(String[] args)
    {
        String search = "other";

        String str = "this is \"my\" example other string. And \"my other\" this is my str in no quotes.";

        Pattern p = Pattern.compile("\"([^\"]*)\"");
        Matcher m = p.matcher(str);

        List<Pair> deadZones = new ArrayList<Pair>();
        while (m.find())
        {
            int s = m.start();
            int e = m.end();
            deadZones.add(new Pair(s, e - 1));
        }

        List<Pair> hitZones = new ArrayList<Pair>();
        p = Pattern.compile(search);
        m = p.matcher(str);
        while (m.find())
        {
            int s = m.start();
            int e = m.end();
            hitZones.add(new Pair(s, e - 1));
        }

        System.out.println(deadZones);
        System.out.println(hitZones);
    }
}

注意hitZones 中所有Pairs 中的s 组件,不在deadZones 内,最终将是您想要的。

【讨论】:

  • 这是一个可行的解决方案,但它绝对不是简单的,看起来我的实现当时还不错。谢谢。
  • 没问题。很高兴我能提供一些见解。
【解决方案2】:

正如 Mamun 所建议的,您可以删除引号之间的所有引号和字符串,然后进行搜索。以下是一个正则表达式解决方案(尽管我同意蒂姆的观点,它可能不是正则表达式引擎的工作)。

String snippetQuoteRemoved = snippet.replaceAll("(?:\")(\\w+)(?:\")","");
// Now simply search in snippetQuoteRemoved  

注意:这将寻找\w+,即([a-zA-Z0-9_])。将其更改为适合您的用例的任何内容。

编辑

我检查了它是否会删除所有内容,但事实并非如此。检查here
此外,对于那些额外的特殊字符,只需将正则表达式更改为 (?:")([a-zA-Z0-9_';:()_\-=+\[\]\{\}]+)(?:")

【讨论】:

  • 是的,如果您更新您的问题并提供更多示例会更好。我会相应地更新答案。
  • 如果引用的部分不止一个,它将删除除开头部分和结尾部分之外的所有内容。
  • 好吧,就像你说的那样工作,但现在我需要保持与以前相同的索引。因此,简单地通过替换为“”来删除是行不通的。
【解决方案3】:

另一种解决方案:

  • 获取sn-p中stringToFind的所有起始索引

  • 获取sn-p中所有引号的索引

  • 取决于stringToFind的起始索引,因为你有引号的位置,你可以知道你是否在引号之间。

    public List<Integer> getOccurrenceIndexesNotInQuotes(String snippet,String patternToFind) {
    
        List<Integer> allIndexes = getStartPositions(snippet,patternToFind);
        List<Integer> allQuoteIndexes = getStartPositions(snippet,"\"");
        TreeSet<Integer> allQuoteIndexesTree = new TreeSet<>(allQuoteIndexes);
    
        List<Integer> finalIndexes = new ArrayList<>();
        for (Integer index : allIndexes){
            Integer quoteIndexValue = allQuoteIndexesTree.floor(index);
            int quoteIndex = allQuoteIndexes.indexOf(quoteIndexValue);
            if (quoteIndexValue == null || !isBetweenQuote(quoteIndex)){
                finalIndexes.add(index);
            }
        }
    
        return finalIndexes;
    }
    
    private List<Integer> getStartPositions(String stringToProcess, String regex) {
        List<Integer> out = new ArrayList<>();
    
        Matcher matcher = Pattern.compile(regex).matcher(stringToProcess);
        while(matcher.find()) {
            out.add(matcher.start());
        }
    
        return out;
    }
    
    private boolean isBetweenQuote(Integer indexInQuoteList){
        return indexInQuoteList % 2 != 1;
    }
    

【讨论】:

    猜你喜欢
    • 2017-06-18
    • 1970-01-01
    • 2020-01-24
    • 1970-01-01
    • 2019-09-08
    • 1970-01-01
    • 2012-03-20
    • 2017-06-04
    相关资源
    最近更新 更多