المُقدّمة
يعد حساب عدد تكرارات الكلمات في سلسلة مهمة سهلة إلى حد ما ، ولكن له عدة طرق للقيام بذلك. يجب عليك أيضًا مراعاة كفاءة الطريقة ، نظرًا لأنك سترغب عادةً في استخدام أدوات آلية عندما لا ترغب في أداء العمل اليدوي - أي عندما تكون مساحة البحث كبيرة.
في هذا الدليل ، ستتعلم كيفية حساب عدد تكرارات الكلمات في سلسلة في Java:
String searchText = "Your body may be chrome, but the heart never changes. It wants what it wants.";
String targetWord = "wants";
سنبحث عن عدد تكرارات ملف targetWord
، وذلك باستخدام String.split()
, Collections.frequency()
والتعبيرات العادية.
عد مرات حدوث الكلمات في سلسلة مع String.split ()
إن أبسط طريقة لحساب حدوث كلمة هدف في سلسلة هي تقسيم السلسلة على كل كلمة ، والتكرار خلال المصفوفة ، وزيادة wordCount
في كل مباراة. لاحظ أنه عندما تحتوي الكلمة على أي نوع من علامات الترقيم حولها ، مثل wants.
في نهاية الجملة - التقسيم البسيط على مستوى الكلمة سيعالج بشكل صحيح wants
و wants.
ككلمات منفصلة!
للتغلب على هذا ، يمكنك بسهولة إزالة جميع علامات الترقيم من الجملة قبل تقسيمها:
String[] words = searchText.replaceAll("p{Punct}", "").split(" ");
int wordCount = 0;
for (int i=0; i < words.length; i++)
if (words[i].equals(targetWord))
wordCount++;
System.out.println(wordCount);
في مجلة for
loop ، نحن ببساطة نكرر المصفوفة ، ونتحقق مما إذا كان العنصر في كل فهرس يساوي targetWord
. إذا كان الأمر كذلك ، فإننا نزيد wordCount
الذي يطبع في نهاية الإعدام:
2
عد مرات حدوث الكلمات في سلسلة مع Collections.frequency ()
• Collections.frequency()
توفر الطريقة تنفيذًا أنظف وأعلى مستوى بكثير ، مما يؤدي إلى تلخيص بسيط for
loop ، والتحقق من الهوية (سواء كان كائنًا is كائن آخر) والمساواة (ما إذا كان الكائن مساويًا لكائن آخر ، اعتمادًا على السمات النوعية لهذا الكائن).
• frequency()
يقبل الأسلوب قائمة للبحث من خلالها ، والكائن الهدف ، ويعمل مع جميع الكائنات الأخرى أيضًا ، حيث يعتمد السلوك على كيفية تنفيذ الكائن نفسه equals()
. في حالة الأوتار ، equals()
يتحقق من محتويات السلسلة:
searchText = searchText.replaceAll("p{Punct}", "");
int wordCount = Collections.frequency(Arrays.asList(searchText.split(" ")), targetWord);
System.out.println(wordCount);
هنا ، قمنا بتحويل المصفوفة التي تم الحصول عليها من split()
في جافا ArrayList
، باستخدام المساعد asList()
طريقة Arrays
صف دراسي. عملية التخفيض frequency()
يُرجع عددًا صحيحًا يشير إلى تكرار targetWord
في القائمة ، والنتائج في:
2
تواجد الكلمات في سلسلة مع المطابق (التعبيرات العادية - RegEx)
أخيرًا ، يمكنك استخدام التعبيرات العادية للبحث عن الأنماط وإحصاء عدد الأنماط المتطابقة. تم تصميم التعبيرات العادية لهذا الغرض ، لذا فهي مناسبة جدًا للمهمة. في جافا ، فإن ملف Pattern
تُستخدم الفئة لتمثيل التعبيرات العادية وتجميعها ، و Matcher
فئة تستخدم للعثور على الأنماط ومطابقتها.
باستخدام RegEx ، يمكننا ترميز ثوابت علامات الترقيم في التعبير نفسه ، لذلك ليست هناك حاجة لتنسيق السلسلة خارجيًا أو إزالة علامات الترقيم ، وهو أمر مفضل للنصوص الكبيرة حيث قد يكون تخزين نسخة معدلة أخرى في الذاكرة مكلفًا:
Pattern pattern = Pattern.compile("b%s(?!w)".format(targetWord));
Pattern pattern = Pattern.compile("bwants(?!w)");
Matcher matcher = pattern.matcher(searchText);
int wordCount = 0;
while (matcher.find())
wordCount++;
System.out.println(wordCount);
وينتج عن ذلك أيضًا:
2
معيار الكفاءة
إذن ، ما هو الأكثر كفاءة؟ لنجري معيارًا صغيرًا:
int runs = 100000;
long start1 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
int result = countOccurencesWithSplit(searchText, targetWord);
}
long end1 = System.currentTimeMillis();
System.out.println(String.format("Array split approach took: %s miliseconds", end1-start1));
long start2 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
int result = countOccurencesWithCollections(searchText, targetWord);
}
long end2 = System.currentTimeMillis();
System.out.println(String.format("Collections.frequency() approach took: %s miliseconds", end2-start2));
long start3 = System.currentTimeMillis();
for (int i = 0; i < runs; i++) {
int result = countOccurencesWithRegex(searchText, targetWord);
}
long end3 = System.currentTimeMillis();
System.out.println(String.format("Regex approach took: %s miliseconds", end3-start3));
سيتم تشغيل كل طريقة 100000 مرة (كلما زاد الرقم ، انخفض التباين والنتائج بسبب الصدفة ، بسبب قانون الأعداد الكبيرة). يؤدي تشغيل هذا الرمز إلى:
Array split approach took: 152 miliseconds
Collections.frequency() approach took: 140 miliseconds
Regex approach took: 92 miliseconds
ومع ذلك - ماذا يحدث إذا جعلنا البحث أكثر تكلفة من الناحية الحسابية من خلال جعله أكبر؟ لننشئ جملة اصطناعية:
List possibleWords = Arrays.asList("hello", "world ");
StringBuffer searchTextBuffer = new StringBuffer();
for (int i = 0; i < 100; i++) {
searchTextBuffer.append(String.join(" ", possibleWords));
}
System.out.println(searchTextBuffer);
يؤدي هذا إلى إنشاء سلسلة بالمحتويات:
hello world hello world hello world hello ...
تحقق من دليلنا العملي العملي لتعلم Git ، مع أفضل الممارسات ، والمعايير المقبولة في الصناعة ، وورقة الغش المضمنة. توقف عن أوامر Googling Git وفي الواقع تعلم ذلك!
الآن ، إذا أردنا البحث عن "hello" أو "world" - فسيكون هناك العديد من المطابقات أكثر من الاثنين من قبل. كيف أساليبنا الآن في المعيار؟
Array split approach took: 606 miliseconds
Collections.frequency() approach took: 899 miliseconds
Regex approach took: 801 miliseconds
الآن ، يتم تقسيم الصفيف بشكل أسرع! بشكل عام ، تعتمد المعايير على عوامل مختلفة - مثل مساحة البحث ، والكلمة المستهدفة ، وما إلى ذلك ، وقد تختلف حالة الاستخدام الشخصي عن المعيار.
المشورة: جرب الطرق على النص الخاص بك ، ولاحظ الأوقات ، واختر الطريقة الأكثر فاعلية وأناقة بالنسبة لك.
وفي الختام
في هذا الدليل المختصر ، ألقينا نظرة على كيفية حساب تكرارات الكلمة لكلمة مستهدفة ، في سلسلة في Java. لقد بدأنا بتقسيم الخيط واستخدام عداد بسيط ، متبوعًا باستخدام Collections
فئة المساعد ، وأخيرًا ، استخدام التعبيرات العادية.
في النهاية ، قمنا بقياس الطرق ، ولاحظنا أن الأداء ليس خطيًا ، ويعتمد على مساحة البحث. بالنسبة لنصوص الإدخال الأطول مع العديد من التطابقات ، يبدو أن المصفوفات المنقسمة هي الأكثر أداءً. جرب الطرق الثلاث بمفردك ، واختر الطريقة الأكثر أداءً.