جافا: حساب عدد الكلمات التي تحدث في السلسلة

المُقدّمة

يعد حساب عدد تكرارات الكلمات في سلسلة مهمة سهلة إلى حد ما ، ولكن له عدة طرق للقيام بذلك. يجب عليك أيضًا مراعاة كفاءة الطريقة ، نظرًا لأنك سترغب عادةً في استخدام أدوات آلية عندما لا ترغب في أداء العمل اليدوي - أي عندما تكون مساحة البحث كبيرة.

في هذا الدليل ، ستتعلم كيفية حساب عدد تكرارات الكلمات في سلسلة في 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 فئة المساعد ، وأخيرًا ، استخدام التعبيرات العادية.

في النهاية ، قمنا بقياس الطرق ، ولاحظنا أن الأداء ليس خطيًا ، ويعتمد على مساحة البحث. بالنسبة لنصوص الإدخال الأطول مع العديد من التطابقات ، يبدو أن المصفوفات المنقسمة هي الأكثر أداءً. جرب الطرق الثلاث بمفردك ، واختر الطريقة الأكثر أداءً.

الطابع الزمني:

اكثر من ستاكابوز