2本の弦があるとします。
String s1 = "AbBaCca";
String s2 = "bac";
s2
がs1
内に含まれていることを返すチェックを実行したいです。私はこれを行うことができます:
return s1.contains(s2);
私はcontains()
が大文字と小文字を区別することを確信しています、しかし私はドキュメンテーションを読むことから確かにこれを決定することができません。もしそうなら、私の最善の方法は次のようになると思います。
return s1.toLowerCase().contains(s2.toLowerCase());
これ以外にも、大文字と小文字の区別を気にせずにこれを達成するための別の(おそらくより良い)方法はありますか?
はい、含むは大文字と小文字を区別します。大文字と小文字を区別しないで一致させるには、CASE_INSENSITIVEフラグを指定してJava.util.regex.Patternを使用できます。
Pattern.compile(Pattern.quote(wantedStr), Pattern.CASE_INSENSITIVE).matcher(source).find();
EDIT:s2に正規表現の特殊文字(たくさんある)が含まれている場合は、最初に引用符を付けることが重要です。それが人々が最初に見るものであるので私は私の答えを修正しました、しかし彼がこれを指摘したのでマットクアイルのものを投票してください。
Dave L.による答え に関する問題の1つは、s2に\d
などの正規表現マークアップが含まれている場合です。
あなたはs2でPattern.quote()を呼び出したいです。
Pattern.compile(Pattern.quote(s2), Pattern.CASE_INSENSITIVE).matcher(s1).find();
あなたが使用することができます
org.Apache.commons.lang3.StringUtils.containsIgnoreCase("AbBaCca", "bac");
Apache Commons ライブラリはこのようなことに非常に便利です。正規表現はパフォーマンスの点で常に高価であるため、そしてこの特定のものは正規表現よりも良いかもしれません。
String.regionMatches()
の利用正規表現の使用は比較的遅くなる可能性があります。あなたがただ一つのケースをチェックインしたいのであれば、それは(遅い)問題ではありません。しかし、数千または数十万の文字列の配列またはコレクションがあると、処理がかなり遅くなる可能性があります。
以下に提示する解決策は正規表現もtoLowerCase()
も使用しません(これは別の文字列を作成し、チェックの後にそれらを捨てるだけなので遅いです)。
解決策は String.regionMatches() メソッドに基づいていますが、不明のようです。 2つのString
領域が一致するかどうかをチェックしますが、重要なことは便利なignoreCase
パラメータを持つオーバーロードもあるということです。
public static boolean containsIgnoreCase(String src, String what) {
final int length = what.length();
if (length == 0)
return true; // Empty string is contained
final char firstLo = Character.toLowerCase(what.charAt(0));
final char firstUp = Character.toUpperCase(what.charAt(0));
for (int i = src.length() - length; i >= 0; i--) {
// Quick check before calling the more expensive regionMatches() method:
final char ch = src.charAt(i);
if (ch != firstLo && ch != firstUp)
continue;
if (src.regionMatches(true, i, what, 0, length))
return true;
}
return false;
}
この速度分析は、ロケット科学であることを意味するのではなく、さまざまな方法がいかに速いかの大まかな図にすぎません。
5つの方法を比較します。
String.contains()
を呼び出します。String.contains()
を呼び出します。このソリューションは、事前定義されたサブストリングをテストするため、すでにそれほど柔軟ではありません。Pattern.compile().matcher().find()
...)Pattern
を使用します。この解決策は、事前定義された部分文字列をテストするため、すでにそれほど柔軟ではありません。結果(メソッドを1000万回呼び出すことによって):
Pattern
を持つ正規表現:1845 msテーブルの結果:
RELATIVE SPEED 1/RELATIVE SPEED
METHOD EXEC TIME TO SLOWEST TO FASTEST (#1)
------------------------------------------------------------------------------
1. Using regionMatches() 670 ms 10.7x 1.0x
2. 2x lowercase+contains 2829 ms 2.5x 4.2x
3. 1x lowercase+contains cache 2446 ms 2.9x 3.7x
4. Regexp 7180 ms 1.0x 10.7x
5. Regexp+cached pattern 1845 ms 3.9x 2.8x
私たちの方法は4倍速くはcontains()
を使って、10倍速いは/を使ってPattern
が事前キャッシュされていても3倍高速(そして任意の部分文字列をチェックする柔軟性を失う)。
分析がどのように行われたかに興味があるなら、これが完全に実行可能なアプリケーションです。
import Java.util.regex.Pattern;
public class ContainsAnalysis {
// Case 1 utilizing String.regionMatches()
public static boolean containsIgnoreCase(String src, String what) {
final int length = what.length();
if (length == 0)
return true; // Empty string is contained
final char firstLo = Character.toLowerCase(what.charAt(0));
final char firstUp = Character.toUpperCase(what.charAt(0));
for (int i = src.length() - length; i >= 0; i--) {
// Quick check before calling the more expensive regionMatches()
// method:
final char ch = src.charAt(i);
if (ch != firstLo && ch != firstUp)
continue;
if (src.regionMatches(true, i, what, 0, length))
return true;
}
return false;
}
// Case 2 with 2x toLowerCase() and contains()
public static boolean containsConverting(String src, String what) {
return src.toLowerCase().contains(what.toLowerCase());
}
// The cached substring for case 3
private static final String S = "i am".toLowerCase();
// Case 3 with pre-cached substring and 1x toLowerCase() and contains()
public static boolean containsConverting(String src) {
return src.toLowerCase().contains(S);
}
// Case 4 with regexp
public static boolean containsIgnoreCaseRegexp(String src, String what) {
return Pattern.compile(Pattern.quote(what), Pattern.CASE_INSENSITIVE)
.matcher(src).find();
}
// The cached pattern for case 5
private static final Pattern P = Pattern.compile(
Pattern.quote("i am"), Pattern.CASE_INSENSITIVE);
// Case 5 with pre-cached Pattern
public static boolean containsIgnoreCaseRegexp(String src) {
return P.matcher(src).find();
}
// Main method: perfroms speed analysis on different contains methods
// (case ignored)
public static void main(String[] args) throws Exception {
final String src = "Hi, I am Adam";
final String what = "i am";
long start, end;
final int N = 10_000_000;
start = System.nanoTime();
for (int i = 0; i < N; i++)
containsIgnoreCase(src, what);
end = System.nanoTime();
System.out.println("Case 1 took " + ((end - start) / 1000000) + "ms");
start = System.nanoTime();
for (int i = 0; i < N; i++)
containsConverting(src, what);
end = System.nanoTime();
System.out.println("Case 2 took " + ((end - start) / 1000000) + "ms");
start = System.nanoTime();
for (int i = 0; i < N; i++)
containsConverting(src);
end = System.nanoTime();
System.out.println("Case 3 took " + ((end - start) / 1000000) + "ms");
start = System.nanoTime();
for (int i = 0; i < N; i++)
containsIgnoreCaseRegexp(src, what);
end = System.nanoTime();
System.out.println("Case 4 took " + ((end - start) / 1000000) + "ms");
start = System.nanoTime();
for (int i = 0; i < N; i++)
containsIgnoreCaseRegexp(src);
end = System.nanoTime();
System.out.println("Case 5 took " + ((end - start) / 1000000) + "ms");
}
}
これを行うより簡単な方法は(パターンマッチングを気にせずに)両方のString
を小文字に変換することです。
String foobar = "fooBar";
String bar = "FOO";
if (foobar.toLowerCase().contains(bar.toLowerCase()) {
System.out.println("It's a match!");
}
はい、これは達成可能です:
String s1 = "abBaCca";
String s2 = "bac";
String s1Lower = s1;
//s1Lower is exact same string, now convert it to lowercase, I left the s1 intact for print purposes if needed
s1Lower = s1Lower.toLowerCase();
String trueStatement = "FALSE!";
if (s1Lower.contains(s2)) {
//THIS statement will be TRUE
trueStatement = "TRUE!"
}
return trueStatement;
このコードは文字列 "TRUE!"を返します。それはあなたのキャラクターが含まれていることがわかったように。
あなたは 正規表現 を使うことができます、そしてそれは働きます:
boolean found = s1.matches("(?i).*" + s2+ ".*");
大文字と小文字を区別しない文字列の一致を見つけるテストを行いました。 1つのフィールドとしてStringを持つ150,000のオブジェクトすべてのVectorがあり、ストリングに一致するサブセットを見つけたいと思いました。私は3つの方法を試しました:
すべて小文字に変換
for (SongInformation song: songs) {
if (song.artist.toLowerCase().indexOf(pattern.toLowercase() > -1) {
...
}
}
String matches()メソッドを使う
for (SongInformation song: songs) {
if (song.artist.matches("(?i).*" + pattern + ".*")) {
...
}
}
正規表現を使う
Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher("");
for (SongInformation song: songs) {
m.reset(song.artist);
if (m.find()) {
...
}
}
タイミング結果は次のとおりです。
未遂試合:20ミリ秒
低い試合へ:182ミリ秒
ストリング一致:278ミリ秒
正規表現:65ミリ秒
このユースケースでは、正規表現が最も速いようです。
これは、あなたがICU4jを利用すれば作ることができる、Unicodeにやさしいものです。一次強度の比較では大文字と小文字の区別は無視されますが、詳細はロケール依存であると説明されているため、「大文字と小文字の区別なし」はメソッド名には疑問があります。しかし、ユーザーが期待するようにロケール依存であることが望ましいです。
public static boolean containsIgnoreCase(String haystack, String needle) {
return indexOfIgnoreCase(haystack, needle) >= 0;
}
public static int indexOfIgnoreCase(String haystack, String needle) {
StringSearch stringSearch = new StringSearch(needle, haystack);
stringSearch.getCollator().setStrength(Collator.PRIMARY);
return stringSearch.first();
}
あなたの主な質問がここにあるかどうか私にはわかりませんが、はい、.containsは大文字と小文字を区別します。
"AbCd".toLowerCase().contains("abcD".toLowerCase())
AnyMatchでストリームを使用でき、Java 8のを含む
public class Test2 {
public static void main(String[] args) {
String a = "Gina Gini Protijayi Soudipta";
String b = "Gini";
System.out.println(WordPresentOrNot(a, b));
}// main
private static boolean WordPresentOrNot(String a, String b) {
//contains is case sensitive. That's why change it to upper or lower case. Then check
// Here we are using stream with anyMatch
boolean match = Arrays.stream(a.toLowerCase().split(" ")).anyMatch(b.toLowerCase()::contains);
return match;
}
}
String container = " Case SeNsitive ";
String sub = "sen";
if (rcontains(container, sub)) {
System.out.println("no case");
}
public static Boolean rcontains(String container, String sub) {
Boolean b = false;
for (int a = 0; a < container.length() - sub.length() + 1; a++) {
//System.out.println(sub + " to " + container.substring(a, a+sub.length()));
if (sub.equalsIgnoreCase(container.substring(a, a + sub.length()))) {
b = true;
}
}
return b;
}
基本的には、2つの文字列を受け取るメソッドです。これはcontains()の大文字と小文字を区別しないバージョンと想定されています。 containsメソッドを使用するときは、一方の文字列がもう一方の文字列に含まれているかどうかを確認します。
このメソッドは、 "sub"である文字列を取得し、それが "sub"と同じ長さであるコンテナ文字列の部分文字列と等しいかどうかを確認します。 for
ループを見ると、コンテナ文字列の部分文字列( "sub"の長さ)を繰り返していることがわかります。
それぞれの繰り返しは、コンテナ文字列の部分文字列がsubに対してequalsIgnoreCase
であるかどうかを確認します。
URL のように、別のASCII文字列でASCII文字列を検索する必要がある場合は、あなたは私の解決策がより良いことがわかります。私はスピードのためにiczaの方法と私のものをテストしましたそしてここに結果があります:
コード:
public static String lowerCaseAscii(String s) {
if (s == null)
return null;
int len = s.length();
char[] buf = new char[len];
s.getChars(0, len, buf, 0);
for (int i=0; i<len; i++) {
if (buf[i] >= 'A' && buf[i] <= 'Z')
buf[i] += 0x20;
}
return new String(buf);
}
public static boolean containsIgnoreCaseAscii(String str, String searchStr) {
return StringUtils.contains(lowerCaseAscii(str), lowerCaseAscii(searchStr));
}
正規表現フラグを使用する簡単で簡潔な方法があります(大文字と小文字を区別しない{i}):
String s1 = "hello abc efg";
String s2 = "ABC";
s1.matches(".*(?i)"+s2+".*");
/*
* .* denotes every character except line break
* (?i) denotes case insensitivity flag enabled for s2 (String)
* */
または、単純なアプローチを使用して、文字列の大文字小文字を部分文字列の大文字小文字に変換してから、containsメソッドを使用できます。
import Java.text.Normalizer;
import org.Apache.commons.lang3.StringUtils;
public class ContainsIgnoreCase {
public static void main(String[] args) {
String in = " Annulée ";
String key = "annulee";
// 100% Java
if (Normalizer.normalize(in, Normalizer.Form.NFD).replaceAll("[\\p{InCombiningDiacriticalMarks}]", "").toLowerCase().contains(key)) {
System.out.println("OK");
} else {
System.out.println("KO");
}
// use commons.lang lib
if (StringUtils.containsIgnoreCase(Normalizer.normalize(in, Normalizer.Form.NFD).replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""), key)) {
System.out.println("OK");
} else {
System.out.println("KO");
}
}
}