さまざまなキーワードを解析する必要がある文字列があります。たとえば、私は文字列を持っています:
「私は123woodsでお会いしましょう」
そして私のキーワードは
「123woods」「woods」
試合があるときはいつでも報告する必要があります。複数の発生も考慮する必要があります。ただし、これについては、ウッドではなく123ウッドでのみマッチを取得する必要があります。これにより、String.contains()メソッドを使用する必要がなくなります。また、キーワードのリスト/セットを持ち、それらの出現を同時にチェックできるはずです。この例では、「123woods」と「come」がある場合、2回出現します。メソッドの実行は、大きなテキストでは多少高速になるはずです。
私の考えはStringTokenizerを使用することですが、うまく機能するかどうかはわかりません。助言がありますか?
以下の例は、コメントに基づいています。キーワードのリストを使用します。キーワードのリストは、Wordの境界を使用して特定の文字列で検索されます。 Apache Commons LangのStringUtilsを使用して、正規表現を作成し、一致したグループを出力します。
String text = "I will come and meet you at the woods 123woods and all the woods";
List<String> tokens = new ArrayList<String>();
tokens.add("123woods");
tokens.add("woods");
String patternString = "\\b(" + StringUtils.join(tokens, "|") + ")\\b";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
より高いパフォーマンスを探している場合は、 StringSearch :Javaの高性能パターンマッチングアルゴリズムをご覧ください。
他の人が答えたように、正規表現と単語の境界を使用します。
"I will come and meet you at the 123woods".matches(".*\\b123woods\\b.*");
本当でしょう。
"I will come and meet you at the 123woods".matches(".*\\bwoods\\b.*");
偽になります。
これがあなたのために働くことを願っています:
String string = "I will come and meet you at the 123woods";
String keyword = "123woods";
Boolean found = Arrays.asList(string.split(" ")).contains(keyword);
if(found){
System.out.println("Keyword matched the string");
}
Arrays.asList(String.split(" ")).contains("xx")
のようなものはどうですか?
String.split() および 配列に特定の値が含まれているかどうかをテストする方法 を参照してください。
AndroidでStringからmatchExact Wordに移動しました:
String full = "Hello World. How are you ?";
String one = "Hell";
String two = "Hello";
String three = "are";
String four = "ar";
boolean is1 = isContainExactWord(full, one);
boolean is2 = isContainExactWord(full, two);
boolean is3 = isContainExactWord(full, three);
boolean is4 = isContainExactWord(full, four);
Log.i("Contains Result", is1+"-"+is2+"-"+is3+"-"+is4);
Result: false-true-true-false
マッチワードの機能:
private boolean isContainExactWord(String fullString, String partWord){
String pattern = "\\b"+partWord+"\\b";
Pattern p=Pattern.compile(pattern);
Matcher m=p.matcher(fullString);
return m.find();
}
完了
正規表現を使用して一致するようにしてください。 「\ b123wood\b」に一致、\ bはワードブレークです。
解決策は長い間受け入れられているようですが、解決策は改善される可能性があるため、誰かが同様の問題を抱えている場合:
これは、マルチパターン検索アルゴリズムの古典的なアプリケーションです。
Javaパターン検索(Matcher.find
)はそれを行う資格がありません。 1つのキーワードの検索はJavaで最適化されます。or-expressionの検索では、不一致を追跡する正規表現非決定性オートマトンが使用されます。最悪の場合、テキストの各文字はl回処理されます(lはパターンの長さの合計です)。
単一パターン検索の方が適していますが、修飾されていません。すべてのキーワードパターンに対して検索全体を開始する必要があります。最悪の場合、テキストの各文字がp回処理されます。pはパターンの数です。
マルチパターン検索は、テキストの各文字を1回だけ処理します。このような検索に適したアルゴリズムは、Aho-Corasick、Wu-Manber、またはSet Backwards Oracle Matchingです。これらは Stringsearchalgorithms または byteseek のようなライブラリで見つけることができます。
// example with StringSearchAlgorithms
AhoCorasick stringSearch = new AhoCorasick(asList("123woods", "woods"));
CharProvider text = new StringCharProvider("I will come and meet you at the woods 123woods and all the woods", 0);
StringFinder Finder = stringSearch.createFinder(text);
List<StringMatch> all = Finder.findAll();
これを行うもっと簡単な方法はsplit()を使用することです:
String match = "123woods";
String text = "I will come and meet you at the 123woods";
String[] sentence = text.split();
for(String Word: sentence)
{
if(Word.equals(match))
return true;
}
return false;
これは、トークンなどを使用せずに同じことを行う、よりシンプルでエレガントな方法です。
public class FindTextInLine {
String match = "123woods";
String text = "I will come and meet you at the 123woods";
public void findText () {
if (text.contains(match)) {
System.out.println("Keyword matched the string" );
}
}
}
正規表現を使用できます。 MatcherメソッドとPatternメソッドを使用して、目的の出力を取得します
元の質問を振り返ると、特定の文で特定のキーワードを見つけ、出現回数を数え、どこで何かを知る必要があります。私は「どこ」が何を意味するのかよくわかりません(文のインデックスですか?)、それを渡します...私はまだJavaを1ステップずつ学習しているので、そのうちにそれに:-)
共通の文(元の質問の文)に繰り返しキーワードが含まれている可能性があることに注意する必要があります。そのため、検索では特定のキーワードが「存在するかどうか」を尋ね、存在する場合は1としてカウントすることはできません。同じものが複数ある場合があります。例えば:
// Base sentence (added punctuation, to make it more interesting):
String sentence = "Say that 123 of us will come by and meet you, "
+ "say, at the woods of 123woods.";
// Split it (punctuation taken in consideration, as well):
Java.util.List<String> strings =
Java.util.Arrays.asList(sentence.split(" |,|\\."));
// My keywords:
Java.util.ArrayList<String> keywords = new Java.util.ArrayList<>();
keywords.add("123woods");
keywords.add("come");
keywords.add("you");
keywords.add("say");
これを見ると、「Say」+「come」+「you」+「say」+「123woods」の期待される結果は5になり、小文字にすると「say」を2回カウントします。そうでない場合、カウントは4で、「Say」が除外され、「say」が含まれます。いいよ私の提案は次のとおりです。
// Set... ready...?
int counter = 0;
// Go!
for(String s : strings)
{
// Asking if the sentence exists in the keywords, not the other
// around, to find repeated keywords in the sentence.
Boolean found = keywords.contains(s.toLowerCase());
if(found)
{
counter ++;
System.out.println("Found: " + s);
}
}
// Statistics:
if (counter > 0)
{
System.out.println("In sentence: " + sentence + "\n"
+ "Count: " + counter);
}
結果は次のとおりです。
発見:言う
見つかった:来る
見つかった:あなた
見つかった:言う
見つかった:123woods
文中:123の森で、私たちの123が来てあなたに会うと言ってください。
カウント:5
\ bフラグ(Wordの境界全体)を使用した正規表現の一致を使用することもできます。
「woods」ではなく「123woods」に一致させるには、正規表現でアトミックグループ化を使用します。 「123woods」だけに一致する文字列では、同じ文字列をさらに検索する代わりに、最初の「123woods」に一致して終了することに注意してください。
\b(?>123woods|woods)\b
プライマリ検索として123woodsを検索し、一致すると検索を終了します。