Τελεστές εύρους και flip-flop#

Δύο τελεστές με δύο εντελώς διαφορετικές εργασίες ανάλογα με το περιβάλλον: σε περιβάλλον λίστας δημιουργούν εύρη, και σε βαθμωτό περιβάλλον είναι εκφράσεις λογικής τιμής με κατάσταση τύπου «flip-flop» για αντιστοίχιση εύρους γραμμών σε επεξεργασία ροής.

Τελεστής

Εργασία σε περιβάλλον λίστας

Εργασία σε βαθμωτό περιβάλλον

..

περιεκτικό εύρος

flip-flop (ελεγμένη-ψευδής εισαγωγή)

...

περιεκτικό εύρος

flip-flop (ελεγμένη-αληθής εισαγωγή)

.. σε περιβάλλον λίστας - εύρη#

Σε περιβάλλον λίστας, ο .. παράγει την περιεκτική ακολουθία μεταξύ των ακραίων σημείων:

0..9                      # (0,1,2,3,4,5,6,7,8,9)
'a'..'z'                  # ('a','b',...,'y','z')      26 elements
'aa'..'zz'                # ('aa','ab',...,'zy','zz')  676 elements
'A'..'F'                  # ('A','B','C','D','E','F')

for my $i (1..100) { ... }                       # numeric for-loop
for my $name ('alpha'..'omega') { ... }          # alphabetic, magic-incremented

Για αριθμητικά ακραία σημεία το αποτέλεσμα είναι η ακέραια ακολουθία (με αυστηρή σειρά - η 5..1 είναι κενή λίστα, ποτέ αντεστραμμένη). Για ακραία σημεία συμβολοσειρών χρησιμοποιείται η μαγική αύξηση από ++, που σας δίνει τη φυσική αλφαβητική εξάπλωση (και από 'aa' μέχρι 'zz' τους αναμενόμενους 676 δυόψηφους συνδυασμούς).

Ένα κοινό ιδίωμα Perl:

my @hex = ('0'..'9', 'a'..'f');           # 16 hex digits as strings
my @rev = reverse 1..10;                   # (10,9,8,...,1)
@arr[ 5..9 ]                               # array slice, indexes 5..9
@arr[ -3..-1 ]                             # last three elements

Το εξ ολοκλήρου ακέραιο εύρος μπορεί να είναι πολύ μεγάλο - η 1..1_000_000_000 είναι λίστα ενός δισεκατομμυρίου στοιχείων. Η Perl 5 δημιουργεί νωχελικά τα εύρη βρόχου στη for, οπότε η for my $i (1..1_000_000_000) είναι ασφαλής, αλλά η my @x = 1..1_000_000_000 δεσμεύει ολόκληρο τον πίνακα. Η PetaPerl ακολουθεί τον ίδιο κανόνα.

Αντεστραμμένα ακραία σημεία#

Η 5..1 είναι κενή. Δεν υπάρχει μορφή «αντεστραμμένου εύρους»· αν θέλετε φθίνουσα σειρά, δημιουργήστε αύξουσα και κάντε reverse:

1..5                    # (1,2,3,4,5)
5..1                    # ()        - empty, no warning
reverse 1..5            # (5,4,3,2,1)

Ακραία σημεία μικτού τύπου#

Αν κάποιο ακραίο σημείο μοιάζει αριθμητικό, ο .. κάνει αριθμητικό εύρος:

'1'..'5'                # (1,2,3,4,5)            - numeric
'1'..'10'               # (1,2,3,4,5,6,7,8,9,10) - numeric

'a'..'5'                # ('a')                  - magic-increment from "a",
                        #                         stops because it can't reach "5"

Κάντε τον τύπο ρητό για αποφυγή σύγχυσης:

0+'1' .. 0+'5'          # numeric, no doubt
sprintf("%d", 1) .. sprintf("%d", 5)

Στην πράξη, γράψτε ακέραια εύρη με σκέτα κυριολεκτικά ακεραίων και εύρη χαρακτήρων με σκέτα γράμματα σε εισαγωγικά· η διάκριση μαγικής-έναντι-αριθμητικής ακολουθεί αυτόματα.

.. και ... σε βαθμωτό περιβάλλον - flip-flops#

Μέσα σε λογικό περιβάλλον (ένα if, ένα while, ένα ?:, τα δεξιά ενός &&/||///), ο .. γίνεται μια έκφραση με κατάσταση που θυμάται αν βρίσκεται αυτή τη στιγμή μεταξύ αντιστοιχίας αριστερής πλευράς και αντιστοιχίας δεξιάς πλευράς.

while (<$fh>) {
    if (/^BEGIN/ .. /^END/) {     # true from BEGIN line through END line
        print;                     # print everything in between, inclusive
    }
}

Η σημασιολογία:

  1. Το flip-flop είναι αρχικά ψευδές.

  2. Όταν η αριστερή συνθήκη (/^BEGIN/) γίνει αληθής, το flip-flop μεταβαίνει σε αληθές, και η δεξιά πλευρά αποτιμάται αμέσως στην ίδια επανάληψη.

  3. Το flip-flop παραμένει αληθές στις επόμενες επαναλήψεις μέχρι η δεξιά συνθήκη (/^END/) να γίνει αληθής. Σε εκείνη την επανάληψη επιστρέφει αληθές και στη συνέχεια μεταβαίνει πάλι σε ψευδές.

  4. Έτσι τόσο η γραμμή BEGIN όσο και η γραμμή END συμπεριλαμβάνονται.

Όταν το flip-flop είναι αληθές, επιστρέφει έναν αύξοντα αριθμό (1 στην επανάληψη εισόδου, 2 στην επόμενη, …). Στην κλείνουσα επανάληψη επιστρέφει το πλήθος ακολουθούμενο από E0 - οπότε η τιμή είναι αληθής (μη κενή συμβολοσειρά, όχι το ψευδές "0") αλλά μετατρέπεται σε συμβολοσειρά ως ο αριθμός 0 για κοσμητική σαφήνεια. Συνήθως μπορείτε να το αντιμετωπίσετε ως απλή λογική τιμή.

Ο ... διαφέρει από τον .. σε μία λεπτομέρεια:

  • .. (δύο τελείες) - όταν η αριστερή πλευρά γίνει αληθής, η δεξιά πλευρά ελέγχεται στην ίδια επανάληψη. Έτσι η ίδια γραμμή μπορεί να ανοίξει και να κλείσει το εύρος.

  • ... (τρεις τελείες) - όταν η αριστερή πλευρά γίνει αληθής, η δεξιά πλευρά δεν ελέγχεται μέχρι την επόμενη επανάληψη. Πάντα εύρος πολλαπλών γραμμών.

while (<$fh>) {
    print if /<head>/ .. /<\/head>/;     # one-line <head>...</head> works
    print if /<head>/ ... /<\/head>/;    # forces multi-line; same-line ignored
}

Πότε θα χρησιμοποιούσατε flip-flop#

Το flip-flop λάμπει στο φιλτράρισμα εύρους γραμμών τύπου awk - εξαγωγή τμημάτων από αρχείο καταγραφής, απομόνωση περιφραγμένου μπλοκ κώδικα από markdown, επεξεργασία μπλοκ ρυθμίσεων οριοθετημένου από λέξεις-κλειδιά. Είναι γνωστά μη-αγαπημένο από ελεγκτές κώδικα επειδή η κατάστασή του είναι σιωπηρή.

Δύο πρακτικές εναλλακτικές που ορισμένοι προτιμούν:

# Explicit state variable - equivalent semantics, easier to grep for:
my $in_block = 0;
while (<$fh>) {
    $in_block = 1 if /^BEGIN/;
    print if $in_block;
    $in_block = 0 if /^END/;
}

# A simple two-step iterator:
while (<$fh>) {
    if (/^BEGIN/ .. /^END/) { print }
}

Το flip-flop κερδίζει σε συντομία· η ρητή μορφή κερδίζει σε σαφήνεια με κόστος τρεις παραπάνω γραμμές. Επιλέξτε ανάλογα με το κοινό.

Δείτε επίσης#

  • reverse, grep, map - τελεστές λίστας που συνήθως συντίθενται με εύρη.

  • Subscript - οι τομές πίνακα @arr[1..3] βασίζονται στο εύρος σε περιβάλλον λίστας.

  • Precedence - οι .. και ... βρίσκονται στη γραμμή 17, μεταξύ ||/// και ?:. Σχεδόν πάντα βάζετε παρενθέσεις όταν συνδυάζετε με λογική.