web-dev-qa-db-ja.com

文字列に複数の単語が含まれているかどうかを検出するより良い方法

こんにちは仲間!複数の単語が文字列に可能な限り高速であるかどうかを検出し、そうであれば動作を実行するプログラムを作成しようとしています。できれば、これらの単語の順序も検出したいのですが、これが高速に実行できる場合に限ります。これまでのところ、これは私がやったことです:

if (input.contains("adsf") && input.contains("qwer")) {
    execute();          
}

ご覧のとおり、複数の単語に対してこれを行うのは面倒です。これが唯一の方法ですか、複数のサブストリングを検出するより良い方法がありますか?また、順序を検出する方法はありますか?

16
Silver

配列を使用できます:

String[] matches = new String[] {"adsf", "qwer"};

bool found = false;
for (String s : matches)
{
  if (input.contains(s))
  {
    execute();
    break;
  }
}

これはあなたが投稿したものと同じくらい効率的ですが、より保守的です。より効率的なソリューションを探すことは、コードのボトルネックであることが証明されるまで無視する必要があるマイクロ最適化のように聞こえます。

9
Jack

単語から正規表現を作成します。

Pattern pattern = Pattern.compile("(?=.*adsf)(?=.*qwer)");
if (pattern.matcher(input).find()) {
    execute();
}

詳細については、この回答を参照してください: https://stackoverflow.com/a/470602/66014

34

Java 8でできる、

String[] searchFor= {"asdf", "qwer"};
String input = "asdf qwer";
public static boolean containsItemFromArray(String inputString, String[] items) {
    return Arrays.stream(input).allMatch(searchFor::contains);
}
3
Linus

検索する部分文字列がたくさんある場合、正規表現はおそらくあまり役​​に立ちません。したがって、部分文字列をリストに入れてから、繰り返してinput.indexOf(substring)を呼び出した方が良いでしょう。それぞれに。これは、部分文字列が見つかった場所のintインデックスを返します。各結果(サブストリングが見つからなかったことを意味する-1を除く)をTreeMapindexはキー、サブストリングは値)にスローすると、次のことができます。マップ上でkeys()を呼び出して順番に取得します。

Map<Integer, String> substringIndices = new TreeMap<Integer, String>();
List<String> substrings = new ArrayList<String>();
substrings.add("asdf");
// etc.

for (String substring : substrings) {
  int index = input.indexOf(substring);

  if (index != -1) {
    substringIndices.put(index, substring);
  }
}

for (Integer index : substringIndices.keys()) {
  System.out.println(substringIndices.get(index));
}
1
NRitH

ツリー構造を使用して、コードポイントごとにサブストリングを保持します。これにより、

これは、ニードルセットがほぼ一定の場合にのみ効率的であることに注意してください。ただし、部分文字列を個別に追加または削除する場合は非効率的ではありませんが、多くの文字列をツリー構造に配置するたびに異なる初期化を行うと、確実に遅くなります。

StringSearcher

import Java.util.ArrayList;
import Java.util.Collections;
import Java.util.List;
import Java.util.Map;
import Java.util.HashMap;

class StringSearcher{
    private NeedleTree needles = new NeedleTree(-1);
    private boolean caseSensitive;
    private List<Integer> lengths = new ArrayList<>();
    private int maxLength;

    public StringSearcher(List<String> inputs, boolean caseSensitive){
        this.caseSensitive = caseSensitive;
        for(String input : inputs){
            if(!lengths.contains(input.length())){
                lengths.add(input.length());
            }
            NeedleTree tree = needles;
            for(int i = 0; i < input.length(); i++){
                tree = tree.child(caseSensitive ? input.codePointat(i) : Character.toLowerCase(input.codePointAt(i)));
            }
            tree.markSelfSet();
        }
        maxLength = Collections.max(legnths);
    }

    public boolean matches(String haystack){
        if(!caseSensitive){
            haystack = haystack.toLowerCase();
        }
        for(int i = 0; i < haystack.length(); i++){
            String substring = haystack.substring(i, i + maxLength); // maybe we can even skip this and use from haystack directly?
            NeedleTree tree = needles;
            for(int j = 0; j < substring.maxLength; j++){
                tree = tree.childOrNull(substring.codePointAt(j));
                if(tree == null){
                    break;
                }
                if(tree.isSelfSet()){
                    return true;
                }
            }
        }
        return false;
    }
}

NeedleTree.Java

import Java.util.HashMap;
import Java.util.Map;

class NeedleTree{
    private int codePoint;
    private boolean selfSet;
    private Map<Integer, NeedleTree> children = new HashMap<>();

    public NeedleTree(int codePoint){
        this.codePoint = codePoint;
    }

    public NeedleTree childOrNull(int codePoint){
        return children.get(codePoint);
    }

    public NeedleTree child(int codePoint){
        NeedleTree child = children.get(codePoint);
        if(child == null){
            child = children.put(codePoint, new NeedleTree(codePoint));
        }
        return child;
    }

    public boolean isSelfSet(){
        return selfSet;
    }

    public void markSelfSet(){
        selfSet = true;
    }
}
1
SOFe

より良いアプローチは次のようなものだと思います。複数の値を1つの文字列として追加し、関数のインデックスによってインデックスを検証します

String s = "123"; 
System.out.println(s.indexOf("1")); // 0
System.out.println(s.indexOf("2")); // 1 
System.out.println(s.indexOf("5")); // -1
0
Virendra khade

これは、古典的なインタビューとCSの問題です。

Robin Karpアルゴリズムは通常、人々がインタビューで最初に話すことです。基本的な考え方は、文字列を調べるときに、現在の文字をハッシュに追加することです。ハッシュが一致文字列のいずれかのハッシュと一致する場合、一致する可能性があることがわかります。これにより、一致文字列を前後にスキャンする必要がなくなります。 https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm

そのインタビューの質問の他の典型的なトピックは、検索を高速化するためにトライ構造を考慮することです。大量の一致文字列がある場合は、常に大量の一致文字列をチェックする必要があります。トライ構造は、そのチェックを行うのにより効率的です。 https://en.wikipedia.org/wiki/Trie

追加のアルゴリズムは次のとおりです。-Aho–Corasick https://en.wikipedia.org/wiki/Aho%E2%80%93Corasick_algorithm -Commentz-Walter https://en.wikipedia。 org/wiki/Commentz-Walter_algorithm

0
Thomas Fischer