Eh bien, j'ai essayé et échoué donc, me revoilà.

J'ai besoin de faire correspondre mon modèle de chemin d'abs.

 /public_html/mystuff/10000001/001/10/01.cnt

Je suis en mode dégradé etc.

#!/usr/bin/perl -Tw
use CGI::Carp qw(fatalsToBrowser);
use strict;
use warnings;
$ENV{PATH} = "bin:/usr/bin";
delete ($ENV{qw(IFS CDPATH BASH_ENV ENV)});

J'ai besoin d'ouvrir le même fichier plusieurs fois ou plus et la contamination m'oblige à effacer le nom du fichier à chaque fois. Même si je fais quelque chose de mal, j'ai encore besoin d'aide pour construire ce modèle pour référence future.

my $file = "$var[5]";
if ($file =~ /(\w{1}[\w-\/]*)/) {
$under = "/$1\.cnt";
} else {
ErroR();
}

Vous pouvez voir par ma tentative de débutant que je suis presque désemparé.

J'ai dû ajouter la barre oblique et l'extension à $1 en raison de mon regex mal construit, mais fonctionnel.

J'ai donc besoin d'aide pour apprendre à corriger mon expression afin que $1 représente /public_html/mystuff/10000001/001/10/01.cnt

Quelqu'un pourrait-il me tenir la main ici et me montrer comment faire :

$file =~ /(\w{1}[\w-\/]*)/ correspond à mon chemin absolu /public_html/mystuff/10000001/001/10/01.cnt ?

Merci pour toute aide.

2
Jim_Bo 13 oct. 2009 à 23:40
Au fait, $file = $var[5]; suffit ; pas besoin de citer $var[5]. Voir perldoc. perl.org/… De plus, je suis sûr que vous vous rendez compte que @var est une mauvaise réputation.
 – 
Sinan Ünür
14 oct. 2009 à 00:12
Merci. Oui, "var" était juste improvisé dans ma tentative d'être aussi clair que possible dans la question. J'apprends encore la règle des guillemets ou non. Je comprends les guillemets simples -vs- doubles donc, j'apprends réellement.
 – 
Jim_Bo
14 oct. 2009 à 00:22
1
Pour répondre plus directement à la dernière question : /(\w{1}[\w-\/]*)/ ne correspondra pas à la barre oblique ou à l'extension, car vous n'avez jamais autorisé ceux-ci dans l'expression régulière. Vous auriez besoin de quelque chose comme /\/?(\w{1}[\w-\/\.]*)/. Notez que j'ai ajouté une barre oblique avant facultative et j'ai ajouté la possibilité d'un point après le premier mot. Les réponses ci-dessous sont toujours meilleures, bien sûr - plus spécifiques est meilleure lorsque cela est possible - mais pour le plaisir d'apprendre, je pense qu'il est important d'avoir cette réponse également. :)
 – 
Rini
14 oct. 2009 à 19:06

2 réponses

Meilleure réponse

Modifier : L'utilisation de $ dans le modèle (comme je l'ai fait auparavant) n'est pas recommandée ici car elle peut correspondre à \n à la fin du nom de fichier. Utilisez \z à la place car il correspond sans ambiguïté à la fin de la chaîne.

Soyez aussi précis que possible dans ce que vous recherchez :

my $fn = '/public_html/mystuff/10000001/001/10/01.cnt';

if ( $fn =~ m!
    ^(
        /public_html
        /mystuff
        /[0-9]{8}
        /[0-9]{3}
        /[0-9]{2}
        /[0-9]{2}\.cnt
     )\z!x ) {
     print $1, "\n";
 }

Alternativement, vous pouvez réduire l'espace vertical pris par le code en mettant ce que je suppose être un préfixe commun '/public_html/mystuff' dans une variable et en combinant divers composants dans une construction qr// (voir perldoc perlop) puis utilisez l'opérateur conditionnel ?: :

#!/usr/bin/perl

use strict;
use warnings;

my $fn = '/public_html/mystuff/10000001/001/10/01.cnt';
my $prefix = '/public_html/mystuff';
my $re = qr!^($prefix/[0-9]{8}/[0-9]{3}/[0-9]{2}/[0-9]{2}\.cnt)\z!;

$fn = $fn =~ $re ? $1 : undef;

die "Filename did not match the requirements" unless defined $fn;
print $fn, "\n";

De plus, je ne peux pas réconcilier en utilisant un chemin relatif comme vous le faites dans

$ENV{PATH} = "bin:/usr/bin";

Avec l'utilisation du mode altération. Vouliez-vous dire

$ENV{PATH} = "/bin:/usr/bin";
7
Sinan Ünür 14 oct. 2009 à 00:50
1
Merci @Sinan, je ne savais pas que le $ENV{PATH} n'était pas correct. Tout fonctionnait correctement, mais cela pourrait avoir été un problème à l'avenir. Merci. J'étais aussi très proche de ce modèle en une seule tentative ! J'ai laissé de côté le $!x à la fin et j'ai abandonné par frustration, adaptant celui de ma question. Merci encore.
 – 
Jim_Bo
13 oct. 2009 à 23:59
1
@Jim_Bo: Je pensais que c'était moins encombré mais je vais combiner les deux.
 – 
Sinan Ünür
14 oct. 2009 à 00:03
@Sinan, pourriez-vous également y mettre votre réponse originale. Était un peu plus en vers mais, utile dans ma courbe d'apprentissage. Merci.
 – 
Jim_Bo
14 oct. 2009 à 00:04
La seule suggestion que j'aurais est d'utiliser File::Spec avec ce que vous faites déjà dans cet exemple.
 – 
genio
14 oct. 2009 à 00:20
@genio, j'aime les modules mais, dans ce cas, je voulais éviter d'utiliser des modules et les garder aussi petits que possible. J'aimerais même me débarrasser du module CGI si je peux. Je ne sais pas si je peux. Je vais essayer quand même.
 – 
Jim_Bo
14 oct. 2009 à 00:27

Vous parlez de décontaminer le chemin du fichier à chaque fois. C'est probablement parce que vous ne compartimentez pas les étapes de votre programme.

En général, je décompose ce genre de programmes en étapes. L'une des premières étapes est la validation des données. Avant de laisser le programme continuer, je valide toutes les données que je peux. Si l'un d'entre eux ne correspond pas à ce que j'attends, je ne laisse pas le programme continuer. Je ne veux pas parcourir la moitié de quelque chose d'important (comme insérer des éléments dans une base de données) pour découvrir que quelque chose ne va pas.

Ainsi, lorsque vous obtenez les données, supprimez-les toutes et stockez les valeurs dans une nouvelle structure de données. N'utilisez pas les données d'origine ou les fonctions CGI après cela. Le module CGI est juste là pour transmettre des données à votre programme. Après cela, le reste du programme devrait en savoir le moins possible sur CGI.

Je ne sais pas ce que vous faites, mais c'est presque toujours une odeur de conception de prendre des noms de fichiers réels en entrée.

6
brian d foy 14 oct. 2009 à 02:15