2010-10-02 7 views
4

Possible en double:
How can I manually interpolate string escapes in a Perl string?Comment puis-je convertir des caractères échappés en caractères spéciaux réels en Perl?

Je lis une chaîne à partir d'un fichier particulier. Le problème avec c'est qu'il contient des caractères échappés, comme:

Hello!\nI\'d like to tell you a little \"secret\"... 

Je voudrais qu'il soit imprimé sans séquences d'échappement, comme:

Hello! 
I'd like to tell you a little "secret". 

Je pensais à enlever antislashs et le remplacement double avec single (puisque \ est représenté par \\), mais cela ne m'aide pas avec les problèmes \ n, \ t et ainsi de suite. Avant d'essayer de jouer avec des cordes laides et complexes, je pensais que je demanderais - peut-être que Perl a un mécanisme intégré pour une telle transformation?

Répondre

3

Pour Perl caractère unique backslash escapes, vous pouvez le faire en toute sécurité en utilisant un eval à deux caractères dans le cadre de la substitution. Vous devez mettre dans les caractères qui sont acceptables à interpréter dans la classe de caractères après le \, puis le caractère unique après est eval 'd et inséré dans la chaîne.

Tenir compte:

#!/usr/bin/perl 
use warnings; 
use strict; 

print "\n\n\n\n"; 

while (my $data = <DATA>) { 
    $data=~s/\\([rnt'"\\])/"qq|\\$1|"/gee; 
    print $data; 
} 

__DATA__ 
Hello!\nI\'d like to tell you a little \"secret\". 
A backslask:\\ 
Tab'\t'stop 
line 1\rline 2 (on Unix, "line 1" will get overwritten) 
line 3\\nline 4 (should result in "line 3\\nline 4") 
line 5\r\nline 6 

Sortie:

Hello! 
I'd like to tell you a little "secret". 
A backslask:\ 
Tab' 'stop 
line 2 (on Unix, "line 1" will get overwritten) 
line 3\nline 4 (should result in "line 3\nline 4") 
line 5 
line 6 

La ligne s/\\([rnt'"\\])/"qq|\\$1|"/gee fait le travail.

  • Le \\([rnt'"\\]) possède les caractères acceptables pour l'évaluation à l'intérieur des accolades.

  • La partie gee fait un double eval sur la chaîne de remplacement. La partie "qq|\\$1|" est évaluée deux fois. Le premier eval remplace $1 dans la chaîne, et le second effectue l'interpolation.

Je ne peux pas penser à une combinaison de deux caractères ici qui constituerait une faille de sécurité ...

Cette méthode ne pas accord avec ce qui suit correctement:

  • Les chaînes entre guillemets. Par exemple, Perl n'échapperait pas à la chaîne 'ligne 1 \ ligne 2' à cause des guillemets simples.

  • séquences Escapes qui sont plus longs qu'un seul caractère, comme hex \x1b ou Unicode comme \N{U+...} ou des séquences de contrôle telles que \cD

  • échappe au mouillage, tels que \ L Se LOWER CASE \ E ou \ Umake supérieure cas \ E

Si vous voulez échapper plus complète de remplacement, vous pouvez utiliser cette regex:

#!/usr/bin/perl 
use warnings; 
use strict; 

print "\n\n\n\n"; 

binmode STDOUT, ":utf8"; 

while (my $data = <DATA>) { 
    $data=~s/\\(
     (?:[arnt'"\\]) |    # Single char escapes 
     (?:[ul].) |     # uc or lc next char 
     (?:x[0-9a-fA-F]{2}) |   # 2 digit hex escape 
     (?:x\{[0-9a-fA-F]+\}) |  # more than 2 digit hex 
     (?:\d{2,3}) |     # octal 
     (?:N\{U\+[0-9a-fA-F]{2,4}\}) # unicode by hex 
     )/"qq|\\$1|"/geex; 
    print $data; 
} 

__DATA__ 
Hello!\nI\'d like to tell you a little \"secret\". 
Here is octal: \120 
Here is UNICODE: \N{U+0041} and \N{U+41} and \N{U+263D} 
Here is a little hex:\x50 \x5fa \x{5fa} \x{263B} 
lower case next char \lU \lA 
upper case next char \ua \uu 
A backslask:\\ 
Tab'\t'stop 
line 1\rline 2 (on Unix, "line 1" will get overwritten) 
line 3\\nline 4 (should result in "line 3\\nline 4") 
line 5\r\nline 6 

qui gère toutes Perl escapes sauf:

  1. type fixé (\ Q, \ u, \ L se terminant par \ E)

  2. formes cotés, comme 'don't \n escape in single quotes' ou [not \n in here]

  3. caractères Unicode nommés, tels que \N{THAI CHARACTER SO SO}

  4. Les caractères de contrôle comme \cD (que est facilement ajouté ...)

Mais ce ne faisait pas partie de votre question, je l'ai compris ...

+0

Ce premier remplacement a bien fonctionné, merci! – Neo

3

Je déteste suggérer cela, mais la chaîne eval résoudrait le problème, mais la chaîne eval soulève une foule de problèmes de sécurité et de maintenance. D'où proviennent ces données? Y a-t-il des contrats entre les producteurs de données et vous sur ce que la chaîne tiendra?

#!/usr/bin/perl 

use strict; 
use warnings; 

while (my $input = <DATA>) { 
    #note: this only works if # is not allowed as a character in the string 
    my $string = eval "qq#$input#" or die [email protected]; 
    print $string; 
} 

__DATA__ 
Hello!\nI\'d like to tell you a little \"secret\". 
This is bad @{[print "I have pwned you\n"]}. 

L'autre solution consiste à créer un hachage qui définit toutes les échappements que vous souhaitez implémenter et effectuer une substitution.

+0

Il est une application locale, un script de ligne de commande, utilisée pour analyser les fichiers journaux d'un autre utilitaire . Dans ce cas, je pense qu'éval ne serait pas une violation de la sécurité, n'est-ce pas? – Neo

+0

Évaluez-vous ce qui se trouve dans les fichiers journaux? Si oui, comment les données ont-elles été enregistrées dans le fichier journal? Si tout ce qu'un utilisateur doit faire est de créer le bon message pour casser ou compromettre votre code, alors ils le feront. Une meilleure option consisterait à corriger celui qui écrit les fichiers journaux pour utiliser une méthode standard d'échappement des caractères spéciaux comme celui de la RFC 3986 (c'est-à-dire l'échappement URI). –

+0

essayez Coffre-fort pour cela. – muhmuhten

Questions connexes