Διαδρομές
/
jq
jq
/
Ασκήσεις
/
Κανονικό Chatbot
Κανονικό Chatbot

Κανονικό Chatbot

Άσκηση εκμάθησης

Εισαγωγή

Κανονικές εκφράσεις

Οι κανονικές εκφράσεις (regexes) είναι ακολουθίες χαρακτήρων που καθορίζουν ένα μοτίβο αναζήτησης σε κείμενο.

Η εκμάθηση της σύνταξης των κανονικών εκφράσεων ξεφεύγει από το πεδίο αυτού του θέματος. Θα επικεντρωθούμε στις εκφράσεις που παρέχει το jq για να χρησιμοποιήσεις τις κανονικές εκφράσεις.

Παραλλαγή κανονικών εκφράσεων

Διαφορετικά εργαλεία υλοποιούν διαφορετικές εκδόσεις των κανονικών εκφράσεων. Το jq ενσωματώνει τη βιβλιοθήκη κανονικών εκφράσεων Oniguruma, η οποία είναι σε μεγάλο βαθμό συμβατή με τις κανονικές εκφράσεις της Perl v5.8.

Η συγκεκριμένη σύνταξη που χρησιμοποιεί το jq βρίσκεται στο αποθετήριο GitHub του Oniguruma.

Caution

Το jq δεν έχει κάποια ειδική σύνταξη για τις κανονικές εκφράσεις. Εκφράζονται απλώς ως συμβολοσειρές. Αυτό σημαίνει ότι τυχόν ανάστροφες κάθετοι μέσα στην κανονική έκφραση πρέπει να διαφύγουν μέσα στη συμβολοσειρά.

Για παράδειγμα, η κλάση χαρακτήρων ψηφίου (\d) πρέπει να γραφτεί ως "\\d".

Συναρτήσεις κανονικών εκφράσεων

Οι κανονικές εκφράσεις στο jq περιορίζονται σε ένα σύνολο φίλτρων.

Απλή αντιστοίχιση

Όταν χρειάζεται να ξέρεις αν μια συμβολοσειρά ταιριάζει με ένα μοτίβο, χρησιμοποίησε το φίλτρο test.

STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])

Αυτό το φίλτρο βγάζει ένα boolean (λογική τιμή) αποτέλεσμα.

"Hello World!" | test("W")    # => true
"Goodbye Mars" | test("W")    # => false
Πληροφορίες για την αντιστοίχιση

Όταν χρειάζεται να εξαγάγεις την υποσυμβολοσειρά που όντως ταίριαξε με το μοτίβο, χρησιμοποίησε το φίλτρο match.

STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])

Αυτό το φίλτρο βγάζει:

  • τίποτα, αν δεν υπήρξε αντιστοίχιση, ή
  • ένα αντικείμενο που περιέχει διάφορες ιδιότητες, αν υπήρξε αντιστοίχιση.

Αυτό το παράδειγμα ψάχνει για δύο ίδια συνεχόμενα φωνήεντα χρησιμοποιώντας τη σύνταξη οπισθοαναφοράς, \1.

"Hello World!" | match("([aeiou])\\1")
# => empty

"Goodbye Mars" | match("([aeiou])\\1")
# => {
#      "offset": 1,
#      "length": 2,
#      "string": "oo",
#      "captures": [
#        {
#          "offset": 1,
#          "length": 1,
#          "string": "o",
#          "name": null
#        }
#      ]
#    }

Το φίλτρο match επιστρέφει ένα αντικείμενο για κάθε αντιστοίχιση. Αυτό το παράδειγμα δείχνει τη σημαία "g" εν δράσει, για να βρει όλα τα φωνήεντα.

"Goodbye Mars" | match("[aeiou]"; "g")
# => { "offset": 1, "length": 1, "string": "o", "captures": [] }
#    { "offset": 2, "length": 1, "string": "o", "captures": [] }
#    { "offset": 6, "length": 1, "string": "e", "captures": [] }
#    { "offset": 9, "length": 1, "string": "a", "captures": [] }
Υποσυμβολοσειρές που συλλαμβάνονται

Παρόμοια με το φίλτρο match, το φίλτρο capture επιστρέφει ένα αντικείμενο αν υπήρξε αντιστοίχιση.

STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])

Το αντικείμενο που επιστρέφεται είναι μια αντιστοίχιση των ονομασμένων συλλήψεων.

"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
#      "project": "JIRAISSUE",
#      "issue_num": "1234"
#    }
Μόνο οι υποσυμβολοσειρές

Το φίλτρο scan είναι παρόμοιο με το match με τη σημαία "g".

STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)

Το scan θα βγάλει μια ροή υποσυμβολοσειρών.

"Goodbye Mars" | scan("[aeiou]")
# => "o"
#    "o"
#    "e"
#    "a"

Χρησιμοποίησε τον κατασκευαστή πίνακα [...] για να συλλάβεις τις υποσυμβολοσειρές.

"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]
Διαχωρισμός συμβολοσειράς

Αν ξέρεις τα μέρη της συμβολοσειράς που θέλεις να κρατήσεις, χρησιμοποίησε το match ή το scan. Αν ξέρεις τα μέρη που θέλεις να απορρίψεις, χρησιμοποίησε το split.

STRING | split(REGEX; FLAGS)
Caution

Το φίλτρο split με ένα όρισμα αντιμετωπίζει το όρισμά του ως σταθερή συμβολοσειρά.

Για να χρησιμοποιήσεις κανονική έκφραση με το split, πρέπει να δώσεις το 2ο όρισμα. Δεν πειράζει να χρησιμοποιήσεις μια κενή συμβολοσειρά.

Ένα παράδειγμα που χωρίζει μια συμβολοσειρά σε αυθαίρετα κενά διαστήματα.

"first   second           third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
Αντικαταστάσεις

Τα φίλτρα sub και gsub μπορούν να μετασχηματίσουν τη συμβολοσειρά εισόδου, αντικαθιστώντας τα τμήματα της εισόδου που αντιστοιχίστηκαν με μια συμβολοσειρά αντικατάστασης.

Για να αντικαταστήσεις μόνο την πρώτη αντιστοίχιση, χρησιμοποίησε το sub. Για να αντικαταστήσεις όλες τις αντιστοιχίσεις, χρησιμοποίησε το gsub.

STRING | sub(REGEX; REPLACEMENT)
STRING | sub(REGEX; REPLACEMENT; FLAGS)
STRING | gsub(REGEX; REPLACEMENT)
STRING | gsub(REGEX; REPLACEMENT; FLAGS)
"Goodnight kittens. Goodnight mittens." | sub("night"; " morning")
# => "Good morning kittens. Goodnight mittens."

"Goodnight kittens. Goodnight mittens." | gsub("night"; " morning")
# => "Good morning kittens. Good morning mittens."

Το κείμενο αντικατάστασης μπορεί να αναφέρεται στις υποσυμβολοσειρές που αντιστοιχίστηκαν. Χρησιμοποίησε ονομασμένες συλλήψεις και παρεμβολή συμβολοσειράς.

"Some 3-letter acronyms: gnu, csv, png"
| gsub( "\\b(?<tla>[[:alpha:]]{3})\\b";     # find words 3 letters long
        "\(.tla | ascii_upcase)" )          # upper-case the match
# => "Some 3-letter acronyms: GNU, CSV, PNG"

Σημαίες

Σε όλα τα παραπάνω φίλτρα, το FLAGS είναι μια συμβολοσειρά που αποτελείται από μηδέν ή περισσότερες από τις υποστηριζόμενες σημαίες.

  • g - Καθολική αναζήτηση (βρες όλες τις αντιστοιχίσεις, όχι μόνο την πρώτη)
  • i - Αναζήτηση χωρίς διάκριση πεζών/κεφαλαίων
  • m - Λειτουργία πολλαπλών γραμμών (το '.' θα ταιριάζει με αλλαγές γραμμής)
  • n - Αγνόησε τις κενές αντιστοιχίσεις
  • p - Ενεργοποιούνται και οι δύο λειτουργίες s και m
  • s - Λειτουργία μονής γραμμής ('^' -> '\A', '$' -> '\Z')
  • l - Βρες τις μεγαλύτερες δυνατές αντιστοιχίσεις
  • x - Εκτεταμένη μορφή κανονικών εκφράσεων (αγνόησε τα κενά και τα σχόλια)

Για παράδειγμα

"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")

# or with Extended formatting

"JIRAISSUE-1234" | capture("
                     (?<project>   \\w+ )  # the Jira project
                     -                     # followed by a hyphen
                     (?<issue_num> \\d+ )  # followed by digits
                   "; "x")

Οδηγίες

Έχεις προσληφθεί ως Ειδικός Κανονικών Εκφράσεων σε μια εταιρεία που αναπτύσσει ένα Chatbot.

Βρίσκεται σε ένα πολύ αρχικό στάδιο ανάπτυξης. Η αποστολή σου είναι να χρησιμοποιήσεις Κανονικές Εκφράσεις για να βελτιώσεις την ικανότητα του Chatbot να κατανοεί και να παράγει φυσική γλώσσα.

1. Έλεγξε αν η εντολή είναι έγκυρη

Πέρα από έξυπνο, το Chatbot είναι και πιστός βοηθός. Για να ζητήσει κάποιος κάτι από το Chatbot, πρέπει να πει τη λέξη "Chatbot" στην πρώτη θέση της εντολής. Δεν έχει σημασία αν η λέξη-κλειδί είναι γραμμένη με ΚΕΦΑΛΑΙΑ ή με πεζά. Το σημαντικό είναι η θέση της λέξης.

Υλοποίησε τη συνάρτηση is_valid_command που βοηθά το Chatbot να αναγνωρίζει πότε ο χρήστης δίνει μια εντολή.

"Chatbot, play a song from the 80's." | is_valid_command
# => true
"Hey Chatbot, where is the closest pharmacy?" | is_valid_command
# => false
"CHATBOT, do you have a solution for this challenge?" | is_valid_command
# => true

2. Αφαίρεσε τα κρυπτογραφημένα emoji

Το Chatbot δυσκολεύεται να καταλάβει πώς οι άνθρωποι χρησιμοποιούν τα emoji για να εκφράσουν τα συναισθήματά τους. Όταν το Chatbot λαμβάνει μηνύματα από χρήστες, κάθε emoji αναπαρίσταται ως η συμβολοσειρά "emoji" ακολουθούμενη από έναν αριθμό id.

Υλοποίησε τη μέθοδο remove_emoji που παίρνει μια συμβολοσειρά και αφαιρεί όλα τα emoji από το μήνυμα.

Οι γραμμές που δεν περιέχουν emoji θα πρέπει να επιστρέφονται αμετάβλητες. Απλώς αφαίρεσε τη συμβολοσειρά "emoji". Μην πειράξεις τα κενά.

"I love playing videogames emoji3465 it's one of my hobbies" | remove_emoji
# => "I love playing videogames  it's one of my hobbies"

3. Έλεγξε αν ο αριθμός τηλεφώνου είναι έγκυρος

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

Υλοποίησε τη συνάρτηση check_phone_number.

Αν ο αριθμός είναι έγκυρος, το Chatbot απαντά με ένα μήνυμα που ευχαριστεί τον χρήστη και επιβεβαιώνει τον αριθμό. Αν ο αριθμός δεν είναι έγκυρος, το Chatbot ενημερώνει τον χρήστη ότι ο αριθμός τηλεφώνου δεν είναι έγκυρος.

Η αναμενόμενη μορφή είναι (+NN) NNN-NNN-NNN, όπου το N είναι ένα ψηφίο.

"chatbot my phone number is (+34) 659-771-594" | check_phone_number
# => "Thanks! Your phone number is OK."
"chatbot, call me at 659-771-594" | check_phone_number
# => "Oops, it seems like I can't reach out to 659-771-594."

4. Βρες τον σύνδεσμο της ιστοσελίδας

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

Παράδειγμα συνομιλίας:

Chatbot: Γεια σου χρήστη, θα ήθελα να μάθω πώς να προγραμματίζω σε JavaScript. Ξέρεις καμία ωραία ιστοσελίδα όπου θα μπορούσα να μάθω;

Χρήστης: Έμαθα πολλά από το exercism.org, έχει πολύ ωραίο υλικό εκεί.

Υλοποίησε τη συνάρτηση get_domains που επιστρέφει έναν πίνακα με domains ιστοσελίδων.

"I learned a lot from exercism.org and google.com" | get_domains
# => ["exercism.org", "google.com"]

5. Χαιρέτησε τον χρήστη

Ένα ευγενικό Chatbot μιλά στους χρήστες με το όνομά τους. Όταν ένας χρήστης συστήνεται, το Chatbot μας εντοπίζει το όνομά του και απαντά με έναν φιλικό χαιρετισμό.

Γράψε τη συνάρτηση nice_to_meet_you.

Αν η συμβολοσειρά εισόδου περιέχει "My name is Someone.", πιάσε το όνομα και επέστρεψε τη συμβολοσειρά "Nice to meet you, Someone.".

"My name is Jean-Luc" | nice_to_meet_you
# => "Nice to meet you, Jean-Luc"

6. Πολύ απλή ανάλυση CSV

Υποκύπτοντας στον πειρασμό να προσθέσουμε κι άλλες λειτουργίες, θα προσθέσουμε στο Chatbot μια συνάρτηση ανάλυσης CSV.

Υλοποίησε τη συνάρτηση parse_csv που παίρνει μια συμβολοσειρά και επιστρέφει έναν πίνακα με τα πεδία που προκύπτουν. Ο διαχωριστής πεδίων θα πρέπει να είναι "κόμμα μαζί με προαιρετικά κενά".

Δεν θα ασχοληθούμε με τις οριακές περιπτώσεις της μορφής CSV (όπως πεδία που περιέχουν κόμματα).

"first, second,third,   fourth" | parse_csv
# => ["first", "second", "third", "fourth"]
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
jq Exercism

Έτοιμος να ξεκινήσεις την άσκηση Κανονικό Chatbot;

Γράψου στο Exercism για να μάθεις και να κατακτήσεις jq με 12 έννοιες75 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.