Il modificatore regex di Perl / m corrisponde in modo diverso su Windows?
Domanda
Le seguenti istruzioni Perl si comportano in modo identico su macchine Unixish. Si comportano diversamente su Windows? Se sì, è a causa della magia \ n?
split m/\015\012/ms, $http_msg;
split m/\015\012/s, $http_msg;
Ho ricevuto un fallimento su uno dei miei moduli CPAN da un rilevatore di fumo Win32. Sembra che sia un problema \ r \ n vs \ n. Una modifica che ho apportato di recente è stata l'aggiunta di // m ai miei regex.
Soluzione
Per queste regex:
m/\015\012/ms m/\015\012/s
Sia / m che / s sono privi di significato.
- / s: fa corrispondere anche
.
a\ n
. Il tuo regex non contiene.
- / m: fa corrispondere
^
e$
accanto a\ n
incorporato nella stringa. Il tuo regex non contiene né^
né$
, né i loro sinonimi.
Ciò che è possibile è effettivamente se il tuo handle di input (socket?) funziona in modalità testo, i caratteri \ r
( \ 015
) saranno stati eliminati su Windows.
Quindi, cosa fare? Suggerisco di rendere facoltativi i caratteri \ 015
e dividerli con
/\015?\012/
Non è necessario per / m, / s o persino il m //
principale. Quelli sono solo cult di merci.
Altri suggerimenti
Non esiste un \ n
magico. Sia \ n
che \ r
significano sempre esattamente un carattere e su tutte le piattaforme basate su ASCII che sono \ cJ
e \ cM
rispettivamente. (Le eccezioni sono piattaforme EBCDIC (per ovvie ragioni) e MacOS Classic (dove \ n
e \ r
significano entrambi \ cM
).)
La magia che si verifica su Windows è che quando si esegue l'I / O tramite un handle di file contrassegnato come in modalità testo, \ r \ n
viene tradotto in \ n su lettura e viceversa su scrittura. (Inoltre,
\ cZ
significa sorpresa del fine del file & # 8211; sorpresa!) Questo viene fatto a livello della libreria di runtime C.
Per risolvere il problema devi binmode
il tuo socket per risolvere il problema.
Dovresti anche rimuovere i modificatori / s
e / m
dal tuo pattern: poiché non usi i meta-personaggi il cui comportamento modificano (.
e la coppia ^
/ $
, rispettivamente), non fanno nulla & # 8211; culto delle merci.
Perché hai aggiunto il / m
? Stai cercando di dividere in linea? Per farlo con / m
devi usare ^
o $
nella regex:
my @lines = split /^/m, $big_string;
Tuttavia, se si desidera trattare una stringa grande come linee, è sufficiente aprire un filehandle su un riferimento allo scalare:
open my $string_fh, '<', \ $big_string;
while( <$string_fh> ) {
... process a line
}