Java: Καταμέτρηση αριθμού εμφάνισης λέξεων στη συμβολοσειρά

Κόμβος πηγής: 1719850

Εισαγωγή

Η καταμέτρηση του αριθμού των εμφανίσεων λέξεων σε μια συμβολοσειρά είναι μια αρκετά εύκολη εργασία, αλλά έχει πολλές προσεγγίσεις για να το κάνει. Πρέπει επίσης να λάβετε υπόψη την αποτελεσματικότητα της μεθόδου, καθώς συνήθως θα θέλετε να χρησιμοποιείτε αυτοματοποιημένα εργαλεία όταν δεν θέλετε να κάνετε χειρωνακτική εργασία – δηλαδή όταν ο χώρος αναζήτησης είναι μεγάλος.

Σε αυτόν τον οδηγό, θα μάθετε πώς να μετράτε τον αριθμό των εμφανίσεων λέξεων σε μια συμβολοσειρά στην 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 βρόχο, απλώς επαναλαμβάνουμε μέσω του πίνακα, ελέγχοντας εάν το στοιχείο σε κάθε δείκτη είναι ίσο με το targetWord. Εάν είναι, αυξάνουμε το wordCount, το οποίο στο τέλος της εκτέλεσης εκτυπώνει:

2

Μετρήστε τις εμφανίσεις λέξεων σε συμβολοσειρά με Collections.frequency()

Η Collections.frequency() Η μέθοδος παρέχει μια πολύ πιο καθαρή υλοποίηση υψηλότερου επιπέδου, η οποία αφαιρεί μια απλή for βρόχο και ελέγχει την ταυτότητα και των δύο (είτε πρόκειται για αντικείμενο is άλλο αντικείμενο) και ισότητα (αν ένα αντικείμενο είναι ίσο με ένα άλλο αντικείμενο, ανάλογα με τα ποιοτικά χαρακτηριστικά αυτού του αντικειμένου).

Η frequency() Η μέθοδος δέχεται μια λίστα προς αναζήτηση και το αντικείμενο προορισμού και λειτουργεί και για όλα τα άλλα αντικείμενα, όπου η συμπεριφορά εξαρτάται από τον τρόπο υλοποίησης του ίδιου του αντικειμένου equals(). Στην περίπτωση των χορδών, equals() έλεγχοι για το περιεχόμενο της συμβολοσειράς:


searchText = searchText.replaceAll("p{Punct}", "");

int wordCount = Collections.frequency(Arrays.asList(searchText.split(" ")), targetWord);
System.out.println(wordCount);

Εδώ, έχουμε μετατρέψει τον πίνακα που λαμβάνεται από split() σε Java ArrayList, χρησιμοποιώντας τον βοηθό asList() μέθοδος του Arrays τάξη. Η λειτουργία μείωσης frequency() επιστρέφει έναν ακέραιο που δηλώνει τη συχνότητα του targetWord στη λίστα και έχει ως αποτέλεσμα:

2

Εμφανίσεις λέξεων σε συμβολοσειρά με Ταίριασμα (κανονικές εκφράσεις – RegEx)

Τέλος, μπορείτε να χρησιμοποιήσετε κανονικές εκφράσεις για να αναζητήσετε μοτίβα και να μετρήσετε τον αριθμό των αντιστοιχισμένων μοτίβων. Οι κανονικές εκφράσεις δημιουργούνται για αυτό, επομένως είναι μια πολύ φυσική εφαρμογή για την εργασία. Στην Java, το 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, με βέλτιστες πρακτικές, πρότυπα αποδεκτά από τον κλάδο και συμπεριλαμβανόμενο φύλλο εξαπάτησης. Σταματήστε τις εντολές του Git στο Google και πραγματικά μαθαίνουν το!

Τώρα, αν αναζητούσαμε είτε "γεια" ή "κόσμος" - θα υπήρχαν πολύ περισσότεροι αγώνες από τους δύο προηγούμενους. Πώς λειτουργούν οι μέθοδοί μας τώρα στο σημείο αναφοράς;

Array split approach took: 606 miliseconds
Collections.frequency() approach took: 899 miliseconds
Regex approach took: 801 miliseconds

Τώρα, ο διαχωρισμός συστοιχιών βγαίνει πιο γρήγορα! Γενικά, τα σημεία αναφοράς εξαρτώνται από διάφορους παράγοντες – όπως ο χώρος αναζήτησης, η λέξη-στόχος κ.λπ. και η περίπτωση προσωπικής χρήσης σας μπορεί να διαφέρει από το σημείο αναφοράς.

Συμβουλές: Δοκιμάστε τις μεθόδους στο δικό σας κείμενο, σημειώστε τις ώρες και επιλέξτε την πιο αποτελεσματική και κομψή για εσάς.

Συμπέρασμα

Σε αυτόν τον σύντομο οδηγό, ρίξαμε μια ματιά στον τρόπο μέτρησης των εμφανίσεων λέξεων για μια λέξη-στόχο, σε μια συμβολοσειρά σε Java. Ξεκινήσαμε χωρίζοντας τη συμβολοσειρά και χρησιμοποιώντας έναν απλό μετρητή, ακολουθούμενο από τη χρήση του Collections βοηθητική τάξη και, τέλος, χρησιμοποιώντας κανονικές εκφράσεις.

Στο τέλος, κάναμε συγκριτική αξιολόγηση των μεθόδων και σημειώσαμε ότι η απόδοση δεν είναι γραμμική και εξαρτάται από τον χώρο αναζήτησης. Για μεγαλύτερα κείμενα εισαγωγής με πολλές αντιστοιχίσεις, ο διαχωρισμός πινάκων φαίνεται να είναι ο πιο αποτελεσματικός. Δοκιμάστε και τις τρεις μεθόδους μόνοι σας και επιλέξτε την πιο αποτελεσματική.

Σφραγίδα ώρας:

Περισσότερα από Stackabuse