Κατάσταση filehandle και εκτύπωσης#
Επτά μεταβλητές που κινούν το I/O της Perl. Είναι καθολικές - η ρύθμιση της $/ σε μια ρουτίνα αλλάζει πώς κάθε άλλη ρουτίνα στην ίδια διεργασία διαβάζει από filehandle. Η πειθαρχία που αποτρέπει αυτό να γίνει καταστροφή είναι η local: κάθε αλλαγή σε μεταβλητή αυτής της σελίδας πρέπει να βρίσκεται μέσα σε μπλοκ local εκτός αν το πρόγραμμα πραγματικά θέλει η νέα τιμή να είναι μόνιμη.
Μεταβλητή | Διαβάζεται ως | Προεπιλογή | Χρησιμοποιείται από |
|---|---|---|---|
| διαχωριστής εγγραφών εισόδου |
|
|
| διαχωριστής εγγραφών εξόδου |
|
|
| διαχωριστής πεδίων εξόδου |
|
|
| διαχωριστής λίστας |
| παρεμβολή πίνακα |
`$ | ` | αυτόματη εκκένωση εξόδου |
|
| αριθμός τρέχουσας γραμμής |
| τελευταίο filehandle που διαβάστηκε |
| διαχωριστής δεικτών |
| εξομοίωση πολλαπλών διαστάσεων |
$/ - ο διαχωριστής εγγραφών εισόδου#
Ελέγχει τι αντιμετωπίζουν η <$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.
Δείτε επίσης#
chomp- αφαιρεί ό,τι κρατάει τη δεδομένη στιγμή η$/· ζευγαρώνει με αλλαγές$/.eof- το ιδίωμαclose ARGV if eofπου κάνει τη$.να μετράει ανά αρχείο σε<>.select- επιλέγει το filehandle στο οποίο εφαρμόζονται η$|και τα χωρίς πρόθεμα$,/$\.IO::Handle- παρέχειautoflush,output_record_separator, κ.λπ. ως κλήσεις μεθόδων.local- ο ασφαλής τρόπος αλλαγής οποιασδήποτε μεταβλητής σε αυτή τη σελίδα.Παρεμβολή - πώς η
$"διαμορφώνει την επέκταση πίνακα μέσα σε συμβολοσειρές σε διπλά εισαγωγικά.