একটি দ্রুত বাস্তবায়ন: ব্যবহার String.regionMatches()
রিজেক্সপ ব্যবহার করা তুলনামূলকভাবে ধীর হতে পারে। আপনি যদি কেবল একটি ক্ষেত্রে যাচাই করতে চান তবে এটি (ধীর হয়ে চলছে) কিছু যায় আসে না। তবে আপনার যদি অ্যারে বা কয়েক হাজার বা কয়েক হাজার স্ট্রিংয়ের সংকলন থাকে তবে জিনিসগুলি বেশ ধীর হয়ে যেতে পারে।
নীচের উপস্থাপিত সমাধানটি নিয়মিত অভিব্যক্তি ব্যবহার করে না toLowerCase()
(যা এটি ধীর কারণ এটি অন্য স্ট্রিং তৈরি করে এবং কেবল চেকের পরে এগুলি ফেলে দেয়)।
সমাধানটি স্ট্রিং.গ্রিওনম্যাচগুলি () পদ্ধতিতে তৈরি করে যা অজানা বলে মনে হয়। এটি 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
। এই সমাধানটি ইতিমধ্যে তত নমনীয় নয় কারণ এটি একটি পূর্বনির্ধারিত সাবস্ট্রিং পরীক্ষা করে।
ফলাফল (পদ্ধতিটি 10 মিলিয়ন বার কল করে):
- আমাদের পদ্ধতি: 670 এমএস
- 2x টু লোওয়ারকেস () এবং এতে রয়েছে (): 2829 এমএস
- 1x টুলওয়ারকেস () এবং এতে () ক্যাশেড স্ট্রস্ট্রিং সহ রয়েছে: 2446 এমএস
- Regexp: 7180 এমএস
- ক্যাশেডের সাথে রিজেক্সপ
Pattern
: 1845 এমএস
একটি টেবিলের ফলাফল:
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
আমাদের পদ্ধতি 4x দ্রুত lowercasing এবং ব্যবহার তুলনায় contains()
, দ্রুত 10x রেগুলার এক্সপ্রেশনের এবং ব্যবহার তুলনায় 3x দ্রুত এমনকি যদি Pattern
প্রাক ক্যাসে নিয়ে যাওয়া হয় (এবং একটি অবাধ সাবস্ট্রিং পরীক্ষা করার নমনীয়তা হারানোর)।
বিশ্লেষণ পরীক্ষার কোড
বিশ্লেষণটি কীভাবে সম্পাদিত হয়েছে তা যদি আপনি আগ্রহী হন তবে এখানে সম্পূর্ণ চলমান অ্যাপ্লিকেশনটি রয়েছে:
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");
}
}