Το πακέτο regexp προσφέρει υποστήριξη για κανονικές εκφράσεις στη Go.
Η σύνταξη των κανονικών εκφράσεων που γίνονται δεκτές είναι η ίδια γενική σύνταξη που χρησιμοποιείται από τη Perl, την Python και άλλες γλώσσες.
Τόσο τα μοτίβα αναζήτησης όσο και τα κείμενα εισόδου ερμηνεύονται ως UTF-8.
Όταν χρησιμοποιείς backticks (βαρείες) για να φτιάξεις συμβολοσειρές, οι κάθετοι () to make strings, backslashes () δεν έχουν κανένα ειδικό νόημα και δεν σηματοδοτούν την αρχή ειδικών χαρακτήρων όπως το tab ) don't have any special meaning and don't mark the beginning of special characters like tabs ή η αλλαγή γραμμής or newlines:
"\t\n" // regular string literal with 2 characters: a tab and a newline
`\t\n`// raw string literal with 4 characters: two backslashes, a 't', and an 'n'
Γι' αυτόν τον λόγο, είναι προτιμότερο να χρησιμοποιείς backticks για να φτιάχνεις κανονικές εκφράσεις, γιατί έτσι δεν χρειάζεται να κάνεις escape τις κάθετους:
"\\" // string with a single backslash
`\\` // string with 2 backslashes
RegExp
Για να χρησιμοποιήσεις μια κανονική έκφραση, πρέπει πρώτα να μεταγλωττίσεις το μοτίβο της συμβολοσειράς.
Η μεταγλώττιση εδώ σημαίνει ότι παίρνεις το μοτίβο συμβολοσειράς της κανονικής έκφρασης και το μετατρέπεις σε μια εσωτερική αναπαράσταση που είναι πιο εύκολο να τη χειριστείς.
Χρειάζεται να μεταγλωττίσεις κάθε μοτίβο μόνο μία φορά, κι έπειτα μπορείς να χρησιμοποιήσεις τη μεταγλωττισμένη εκδοχή της κανονικής έκφρασης πολλές φορές.
Ο τύπος regexp.Regexp αναπαριστά μια μεταγλωττισμένη κανονική έκφραση.
Μπορείς να μεταγλωττίσεις ένα μοτίβο συμβολοσειράς σε regexp.Regexp χρησιμοποιώντας τη συνάρτηση regexp.Compile.
Αυτή η συνάρτηση επιστρέφει nil και ένα σφάλμα αν η μεταγλώττιση απέτυχε:
re, err := regexp.Compile(`(a|b)+`)
fmt.Println(re, err) // => (a|b)+ <nil>
re, err = regexp.Compile(`a|b)+`)
fmt.Println(re, err) // => <nil> error parsing regexp: unexpected ): `a|b)+`
Η συνάρτηση MustCompile είναι ένας βολικός εναλλακτικός τρόπος αντί για τη Compile:
re = regexp.MustCompile(`[a-z]+\d*`)
Χρησιμοποιώντας αυτή τη συνάρτηση, δεν χρειάζεται να χειριστείς κάποιο σφάλμα.
Το MustCompile θα πρέπει να χρησιμοποιείται μόνο όταν ξέρουμε σίγουρα ότι το μοτίβο μεταγλωττίζεται, αλλιώς το πρόγραμμα θα πανικοβληθεί.
Υπάρχουν 16 μέθοδοι του Regexp που αντιστοιχίζουν μια κανονική έκφραση και εντοπίζουν το κείμενο που αντιστοιχίστηκε.
Τα ονόματά τους αντιστοιχίζονται από αυτή την κανονική έκφραση:
Find(All)?(String)?(Submatch)?(Index)?
All, η μέθοδος αντιστοιχίζει διαδοχικές μη επικαλυπτόμενες αντιστοιχίσεις ολόκληρης της έκφρασης.String, το όρισμα είναι συμβολοσειρά, αλλιώς είναι ένα τμήμα byte· οι τιμές επιστροφής προσαρμόζονται ανάλογα.Submatch, η τιμή επιστροφής είναι ένα τμήμα που προσδιορίζει τις διαδοχικές υπο-αντιστοιχίσεις της έκφρασης.Index, οι αντιστοιχίσεις και οι υπο-αντιστοιχίσεις προσδιορίζονται από ζεύγη θέσεων byte μέσα στη συμβολοσειρά εισόδου.Υπάρχουν επίσης μέθοδοι για:
Συνολικά, το πακέτο regexp ορίζει περισσότερες από 40 συναρτήσεις και μεθόδους.
Παρακάτω θα δεις τη χρήση μερικών μεθόδων.
Δες την τεκμηρίωση API για λεπτομέρειες σχετικά με αυτές τις συναρτήσεις και άλλες.
MatchString
Η μέθοδος MatchString αναφέρει αν μια συμβολοσειρά περιέχει οποιαδήποτε αντιστοίχιση μιας κανονικής έκφρασης.
re = regexp.MustCompile(`[a-z]+\d*`)
b = re.MatchString("[a12]") // => true
b = re.MatchString("12abc34(ef)") // => true
b = re.MatchString(" abc!") // => true
b = re.MatchString("123 456") // => false
FindString
Η μέθοδος FindString επιστρέφει μια συμβολοσειρά που περιέχει το κείμενο της πιο αριστερής αντιστοίχισης της κανονικής έκφρασης.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.FindString("[a12]") // => "a12"
s = re.FindString("12abc34(ef)") // => "abc34"
s = re.FindString(" abc!") // => "abc"
s = re.FindString("123 456") // => ""
FindStringSubmatch
Η μέθοδος FindStringSubmatch επιστρέφει ένα τμήμα συμβολοσειρών που περιέχει το κείμενο της πιο αριστερής αντιστοίχισης της κανονικής έκφρασης και τις αντιστοιχίσεις, αν υπάρχουν, των υποεκφράσεών της.
Αυτό μπορεί να χρησιμοποιηθεί για να προσδιορίσεις τις συμβολοσειρές που ταιριάζουν με ομάδες σύλληψης.
Μια τιμή επιστροφής nil δηλώνει ότι δεν υπάρχει αντιστοίχιση.
re = regexp.MustCompile(`[a-z]+(\d*)`)
sl = re.FindStringSubmatch("[a12]") // => []string{"a12","12"}
sl = re.FindStringSubmatch("12abc34(ef)") // => []string{"abc34","34"}
sl = re.FindStringSubmatch(" abc!") // => []string{"abc",""}
sl = re.FindStringSubmatch("123 456") // => <nil>
ReplaceAllString
Η μέθοδος re.ReplaceAllString(src,repl) επιστρέφει ένα αντίγραφο του src, αντικαθιστώντας τις αντιστοιχίσεις της κανονικής έκφρασης re με τη συμβολοσειρά αντικατάστασης repl.
re = regexp.MustCompile(`[a-z]+\d*`)
s = re.ReplaceAllString("[a12]", "X") // => "[X]"
s = re.ReplaceAllString("12abc34(ef)", "X") // => "12X(X)"
s = re.ReplaceAllString(" abc!", "X") // => " X!"
s = re.ReplaceAllString("123 456", "X") // => "123 456"
Split
Η μέθοδος re.Split(s,n) τεμαχίζει ένα κείμενο s σε υποσυμβολοσειρές που χωρίζονται από την έκφραση και επιστρέφει ένα τμήμα με τις υποσυμβολοσειρές που βρίσκονται ανάμεσα σε αυτές τις αντιστοιχίσεις της έκφρασης.
Το πλήθος n καθορίζει τον μέγιστο αριθμό υποσυμβολοσειρών που θα επιστραφούν.
Αν n<0, η μέθοδος επιστρέφει όλες τις υποσυμβολοσειρές.
re = regexp.MustCompile(`[a-z]+\d*`)
sl = re.Split("[a12]", -1) // => []string{"[","]"}
sl = re.Split("12abc34(ef)", 2) // => []string{"12","(ef)"}
sl = re.Split(" abc!", -1) // => []string{" ","!"}
sl = re.Split("123 456", -1) // => []string{"123 456"}
Αυτή η άσκηση ασχολείται με την ανάλυση αρχείων καταγραφής.
Μετά από μια πρόσφατη επισκόπηση ασφαλείας, σου ζητήθηκε να τακτοποιήσεις τα αρχειοθετημένα αρχεία καταγραφής του οργανισμού.
Όλες οι συμβολοσειρές που περνούν στις συναρτήσεις είναι εγγυημένο ότι δεν είναι null και δεν έχουν κενά στην αρχή και στο τέλος.
Χρειάζεσαι μια ιδέα για το πόσες γραμμές καταγραφής στο αρχείο σου δεν συμμορφώνονται με τα τρέχοντα πρότυπα. Πιστεύεις ότι ένας απλός έλεγχος αποκαλύπτει αν μια γραμμή καταγραφής είναι έγκυρη. Για να θεωρηθεί έγκυρη, μια γραμμή πρέπει να ξεκινά με μία από τις παρακάτω συμβολοσειρές:
Υλοποίησε τη συνάρτηση IsValidLine ώστε να επιστρέφει false αν μια συμβολοσειρά δεν είναι έγκυρη, αλλιώς true.
IsValidLine("[ERR] A good error here")
// => true
IsValidLine("Any old [ERR] text")
// => false
IsValidLine("[BOB] Any old text")
// => false
Μια νέα ομάδα έχει ενταχθεί στον οργανισμό και ανακαλύπτεις ότι τα αρχεία καταγραφής της χρησιμοποιούν έναν παράξενο διαχωριστικό για τα "πεδία". Αντί για κάτι λογικό όπως μια άνω και κάτω τελεία ":" χρησιμοποιούν μια συμβολοσειρά όπως "<--->" ή "<=>" (επειδή είναι πιο όμορφη), στην πραγματικότητα οποιαδήποτε συμβολοσειρά που έχει πρώτο χαρακτήρα το "<" και τελευταίο χαρακτήρα το ">" και οποιονδήποτε συνδυασμό από τους παρακάτω χαρακτήρες "~", "*", "=" και "-" στο ενδιάμεσο.
Υλοποίησε τη συνάρτηση SplitLogLine που παίρνει μια γραμμή και επιστρέφει έναν πίνακα από συμβολοσειρές, καθεμιά από τις οποίες περιέχει ένα πεδίο.
SplitLogLine("section 1<*>section 2<~~~>section 3")
// => []string{"section 1", "section 2", "section 3"},
password μέσα σε εισαγωγικάΗ ομάδα χρειάζεται να γνωρίζει τις αναφορές σε κωδικούς πρόσβασης μέσα σε εισαγωγικά, ώστε να μπορούν να εξεταστούν χειροκίνητα.
Υλοποίησε τη συνάρτηση CountQuotedPasswords για να δώσεις μια ένδειξη της πιθανής έκτασης της χειροκίνητης εργασίας.
Εντόπισε τις γραμμές καταγραφής όπου η συμβολοσειρά "password", η οποία μπορεί να είναι σε οποιονδήποτε συνδυασμό πεζών ή κεφαλαίων, περικλείεται από εισαγωγικά. Πρέπει να λάβεις υπόψη την πιθανότητα επιπλέον περιεχομένου μέσα στα εισαγωγικά, πριν και μετά το "password". Κάθε γραμμή θα περιέχει το πολύ δύο εισαγωγικά.
Οι γραμμές που περνούν στη ρουτίνα μπορεί να είναι έγκυρες ή όχι όπως ορίζεται στην εργασία 1. Τις επεξεργαζόμαστε με τον ίδιο τρόπο, ανεξάρτητα από το αν είναι έγκυρες.
lines := []string{
`[INF] passWord`, // contains 'password' but not surrounded by quotation marks
`"passWord"`, // count this one
`[INF] User saw error message "Unexpected Error" on page load.`, // does not contain 'password'
`[INF] The message "Please reset your password" was ignored by the user`, // count this one
}
// => 2
Έχεις ανακαλύψει ότι κάποια επεξεργασία των αρχείων καταγραφής πιο πάνω στην αλυσίδα σκορπάει το κείμενο "end-of-line" ακολουθούμενο από έναν αριθμό γραμμής (χωρίς ενδιάμεσο κενό) σε όλα τα αρχεία καταγραφής.
Υλοποίησε τη συνάρτηση RemoveEndOfLineText ώστε να παίρνει μια συμβολοσειρά, να αφαιρεί το κείμενο end-of-line και να επιστρέφει μια "καθαρή" συμβολοσειρά.
Οι γραμμές που δεν περιέχουν το κείμενο end-of-line πρέπει να επιστρέφονται χωρίς αλλαγές.
Απλώς αφαίρεσε τη συμβολοσειρά end-of-line. Μην επιχειρήσεις να προσαρμόσεις τα κενά.
RemoveEndOfLineText("[INF] end-of-line23033 Network Failure end-of-line27")
// => "[INF] Network Failure "
Έχεις παρατηρήσει ότι κάποιες από τις γραμμές καταγραφής περιλαμβάνουν προτάσεις που αναφέρονται σε χρήστες.
Αυτές οι προτάσεις περιέχουν πάντα τη συμβολοσειρά "User", ακολουθούμενη από έναν ή περισσότερους χαρακτήρες κενού και έπειτα από ένα όνομα χρήστη.
Αποφασίζεις να σημειώσεις τέτοιες γραμμές.
Υλοποίησε μια συνάρτηση TagWithUserName που επεξεργάζεται τις γραμμές καταγραφής:
"User " παραμένουν αμετάβλητες."User ", βάλε στην αρχή της γραμμής το [USR] ακολουθούμενο από το όνομα χρήστη.Για παράδειγμα:
result := TagWithUserName([]string{
"[WRN] User James123 has exceeded storage space.",
"[WRN] Host down. User Michelle4 lost connection.",
"[INF] Users can login again after 23:00.",
"[DBG] We need to check that user names are at least 6 chars long.",
})
// => []string {
// "[USR] James123 [WRN] User James123 has exceeded storage space.",
// "[USR] Michelle4 [WRN] Host down. User Michelle4 lost connection.",
// "[INF] Users can login again after 23:00.",
// "[DBG] We need to check that user names are at least 6 chars long."
// }
Μπορείς να υποθέσεις ότι:
"User " σε κάθε γραμμή.Γράψου στο Exercism για να μάθεις και να κατακτήσεις Go με 34 έννοιες165 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.