Κατάσταση filehandle και εκτύπωσης#

Επτά μεταβλητές που κινούν το I/O της Perl. Είναι καθολικές - η ρύθμιση της $/ σε μια ρουτίνα αλλάζει πώς κάθε άλλη ρουτίνα στην ίδια διεργασία διαβάζει από filehandle. Η πειθαρχία που αποτρέπει αυτό να γίνει καταστροφή είναι η local: κάθε αλλαγή σε μεταβλητή αυτής της σελίδας πρέπει να βρίσκεται μέσα σε μπλοκ local εκτός αν το πρόγραμμα πραγματικά θέλει η νέα τιμή να είναι μόνιμη.

Μεταβλητή

Διαβάζεται ως

Προεπιλογή

Χρησιμοποιείται από

$/

διαχωριστής εγγραφών εισόδου

"\n"

<$fh>, readline

$\

διαχωριστής εγγραφών εξόδου

undef

print, printf, say (υποχρεωτικό \n)

$,

διαχωριστής πεδίων εξόδου

undef

print, printf (μεταξύ ορισμάτων)

$"

διαχωριστής λίστας

" "

παρεμβολή πίνακα "@arr"

`$

`

αυτόματη εκκένωση εξόδου

0

$.

αριθμός τρέχουσας γραμμής

0

τελευταίο filehandle που διαβάστηκε

$;

διαχωριστής δεικτών

"\034"

εξομοίωση πολλαπλών διαστάσεων $h{$x, $y}

$/ - ο διαχωριστής εγγραφών εισόδου#

Ελέγχει τι αντιμετωπίζουν η <$fh> και η readline ως τέλος μιας εγγραφής. Η προεπιλογή "\n" σημαίνει ανάγνωση γραμμή-γραμμή· η ρύθμιση σε άλλες τιμές παράγει άλλες λειτουργίες ανάγνωσης.

Λειτουργία γραμμής (η προεπιλογή)#

while (my $line = <$fh>) {
    chomp $line;                 # strips the terminator $/
    process($line);
}

Η chomp αφαιρεί ό,τι κρατάει τη δεδομένη στιγμή η $/ - όταν αλλάξετε τη $/, η chomp την ακολουθεί.

Λειτουργία slurp#

Η undef $/ κάνει τη <> να διαβάσει ολόκληρο το αρχείο μονομιάς:

my $whole_file = do {
    local $/;
    <$fh>;
};

Η local είναι ουσιαστική. Χωρίς αυτή, κάθε άλλο κομμάτι κώδικα που στη συνέχεια διαβάζει από filehandle στην ίδια διεργασία θα κάνει σιωπηρά slurp.

Λειτουργία παραγράφου#

Η local $/ = ""; διαβάζει παράγραφο-παράγραφο, χωρίζοντας σε ακολουθίες δύο ή περισσότερων newlines:

{
    local $/ = "";
    while (my $para = <$fh>) {
        # $para ends with exactly two newlines (or one at EOF)
        process_paragraph($para);
    }
}

Αυτή είναι η συμπεριφορά RS="" του awk. Κενές γραμμές στην αρχή του αρχείου παραλείπονται σιωπηρά.

Λειτουργία σταθερής εγγραφής#

Η local $/ = \N διαβάζει N bytes ανά κλήση:

local $/ = \4096;                # binary 4-KiB chunks
while (defined(my $chunk = <$fh>)) {
    process($chunk);
}

Η αναφορά είναι προς αριθμό, όχι στον ίδιο τον αριθμό. Αυτή είναι η σωστή μορφή για ανάγνωση δυαδικών δεδομένων, πακέτων δικτύου, ή μαζική αντιγραφή χωρίς σάρωση για \n.

Τερματιστές πολλαπλών χαρακτήρων#

local $/ = "\r\n";               # CRLF mode
local $/ = "\nEND-OF-RECORD\n";  # custom marker

Ο τερματιστής είναι κυριολεκτική συμβολοσειρά, όχι regex.

$\ - ο διαχωριστής εγγραφών εξόδου#

Προσαρτάται σε κάθε κλήση print. Η προεπιλογή είναι undef (τίποτα δεν προσαρτάται). Η ρύθμισή της αλλάζει κάθε επόμενο print:

{
    local $\ = "\n";             # all prints get a trailing newline
    print "first";
    print "second";
}
# Output: "first\nsecond\n"

Αυτή είναι η φυσική αντιστοιχία για τη -l στη γραμμή εντολών - η -l θέτει τη $\ σε \n. Σε κώδικα σεναρίου, η local $\ = "\n" μέσα σε σφιχτό βρόχο αναφοράς αξίζει περιστασιακά· αλλιώς η say (που επιβάλλει \n ανεξάρτητα από τη $\) είναι η καθαρότερη γραφή.

$, - ο διαχωριστής πεδίων εξόδου#

Εισάγεται μεταξύ ορισμάτων print. Η προεπιλογή είναι undef:

print "a", "b", "c";              # "abc"

{
    local $, = ", ";
    print "a", "b", "c";          # "a, b, c"
}

{
    local $, = "\t";
    print @items;                 # tab-separated record
}

Η $, εφαρμόζεται ανά print, όχι ανά γραμμή - δεν διαχωρίζει διαδοχικές κλήσεις print. Συνδυάστε με τη $\ για πλήρη έξοδο τύπου TSV:

local ($,, $\) = ("\t", "\n");
print 'col1', 'col2', 'col3';     # "col1\tcol2\tcol3\n"

$" - ο διαχωριστής λίστας#

Ενώνει στοιχεία πίνακα όταν ένας πίνακας παρεμβάλλεται σε συμβολοσειρά σε διπλά εισαγωγικά. Η προεπιλογή είναι " " (ένα κενό):

my @arr = (1, 2, 3);
print "items: @arr\n";            # "items: 1 2 3"

{
    local $" = ', ';
    print "items: @arr\n";        # "items: 1, 2, 3"
}

{
    local $" = "\n  ";
    print "items:\n  @arr\n";     # "items:\n  1\n  2\n  3"
}

Η $" συμβουλεύεται μόνο κατά την παρεμβολή. Η print @arr (χωρίς εισαγωγικά) χρησιμοποιεί τη $,, όχι τη $".

$| - αυτόματη εκκένωση εξόδου#

Επιβάλλει εκκένωση μετά από κάθε εγγραφή στο τρέχον επιλεγμένο filehandle:

$| = 1;                          # autoflush STDOUT
print "Loading..."; sleep 1;     # appears immediately, not at exit

Η διευκρίνιση «τρέχον επιλεγμένο» έχει σημασία. Εξ ορισμού, η select επιστρέφει STDOUT, οπότε η $| = 1 κάνει αυτόματη εκκένωση στο STDOUT. Για αυτόματη εκκένωση σε διαφορετικό handle:

my $old = select($log_fh);
$| = 1;
select($old);                    # restore selection

Η ελαφρώς ωραιότερη σύγχρονη γραφή χρησιμοποιεί την IO::Handle:

$log_fh->autoflush(1);

Η $| διαβάζεται ως λογική τιμή: η print $| εμφανίζει 1 ή 0.

$. - αριθμός τρέχουσας γραμμής#

Ο αριθμός γραμμής της τελευταίας ανάγνωσης τύπου <>. Κάθε filehandle έχει τον δικό του μετρητή· η ανάγνωση από διαφορετικό handle ψευδωνυμεί τη $. στον μετρητή εκείνου του handle:

while (<$fh>) {
    print "$.: $_";              # numbered listing
}

# After the loop, $. is the total number of lines read.

Η $. μηδενίζεται όταν κλείσει το filehandle. Ξανα-άνοιγμα (χωρίς ρητό κλείσιμο ενδιάμεσα) δεν μηδενίζει.

Για επανάληψη πολλαπλών αρχείων μέσω <>, οι γραμμές αριθμούνται σωρευτικά μεταξύ αρχείων εκτός αν κλείσετε ρητά το ARGV σε κάθε όριο αρχείου - δείτε eof για το τυπικό ιδίωμα close ARGV if eof;.

$; - ο διαχωριστής δεικτών#

Χρησιμοποιείται για εξομοίωση πολυδιάστατων hashes - ένα βαθιά παλαιό χαρακτηριστικό που διατηρείται για συμβατότητα προς τα πίσω:

$h{$x, $y} = $value;             # equivalent to $h{"$x\034$y"}

Η προεπιλεγμένη τιμή είναι "\034" (FS, «file separator», ένα σπάνιο byte ελέγχου ASCII). Πραγματικές πολυδιάστατες δομές πρέπει να χρησιμοποιούν ένθετες αναφορές hash ($h{$x}{$y})· η $; υπάρχει επειδή η Perl 4 δεν είχε σωστές αναφορές.

Πότε στην πράξη κάνετε local σε αυτά#

Η πιο συνηθισμένη μορφή, μακράν:

sub slurp_text {
    my ($path) = @_;
    open my $fh, '<', $path or die "open $path: $!";
    local $/;                    # slurp inside this sub only
    return <$fh>;
}

sub paragraphs_of {
    my ($path) = @_;
    open my $fh, '<', $path or die "open $path: $!";
    local $/ = "";
    return <$fh>;                # list context: list of paragraphs
}

sub csv_print {
    my (@row) = @_;
    local ($,, $\) = (",", "\n");
    print @row;
}

Το κόστος του να ξεχάσετε τη local είναι αόρατο κατά τη γραφή και καταστροφικό κατά τη χρήση - μια υπορουτίνα που «απλώς θέτει τη $/» μπορεί να σπάσει άσχετο κώδικα που διαβάζει από εντελώς διαφορετικά filehandles. Αντιμετωπίστε τις $/, $\, $,, $" ως καθολικές σημαίες λειτουργίας: θέτετέ τις πάντα με local.

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

  • open, readline, <$fh> - οι καταναλωτές της $/.

  • print, printf, say - οι καταναλωτές των $\, $,.

  • chomp - αφαιρεί ό,τι κρατάει τη δεδομένη στιγμή η $/· ζευγαρώνει με αλλαγές $/.

  • eof - το ιδίωμα close ARGV if eof που κάνει τη $. να μετράει ανά αρχείο σε <>.

  • select - επιλέγει το filehandle στο οποίο εφαρμόζονται η $| και τα χωρίς πρόθεμα $,/$\.

  • IO::Handle - παρέχει autoflush, output_record_separator, κ.λπ. ως κλήσεις μεθόδων.

  • local - ο ασφαλής τρόπος αλλαγής οποιασδήποτε μεταβλητής σε αυτή τη σελίδα.

  • Παρεμβολή - πώς η $" διαμορφώνει την επέκταση πίνακα μέσα σε συμβολοσειρές σε διπλά εισαγωγικά.