проблемы сравнения переменных, назначенных в выражении foreach - PullRequest
1 голос
/ 12 февраля 2012

Я работал над файлом cgi, который будет проверять, занято ли уже имя пользователя, когда пользователь хочет зарегистрировать свои учетные данные. Если имя пользователя занято, оно должно уведомить их, если нет, то сохраняет их учетные данные в исходный плоский файл. У меня проблемы со сравнением переменных, которым я присвоил значение в выражении foreach. Я говорю foreach назначить имя пользователя переменной, если имя, введенное пользователем, совпадает с именем, которое уже сохранено. Я правильно назначил переменные, но после слов я хочу сказать, чтобы они снова сравнивали эти переменные за пределами foreach, чтобы операция выполнялась только один раз. Вот мой текущий код

#!/usr/bin/perl 
use warnings;
use strict;
use CGI qw(:standard);
use CGI::Carp qw/fatalsToBrowser warningsToBrowser/;
use Digest::MD5 qw(md5 md5_hex md5_base64);

#telling what variables are still to be used as global
our ($username, ,$user, $nametaken);

#assigning some local variables
my $username = param("username");
my $password = param("password");
my $hashpass = md5_hex($password);

print header, start_html();

#creating an array from the flatfile that usernames and passwords are stored
my @users = do { open my $fh, "<", "password.txt" or die $!; map { chomp; split /:/ } <$fh> };

#comparing the values in the array to the username entered
foreach my $user (@users) {
if ($user eq $username) {
    #printing here to test if it is comparing correctly which it is
    print p("$user\n");
    #assigning the $user value to $nametaken so it can be compared to later
    my $nametaken = $user;
    #printing here to test if the variable was correctly assigned, which it is
    print p("$nametaken\n");
    }
}   

#printing here to test if the variable was correctly assigned, which it is not printing
#so the foreach must be causing some king of issue for this variable after it is done and I don't know what that is
print p("$nametaken\n");

#Here is where I am trying to check if the username already exists and then save the user credentials if it does not
if ($nametaken eq $username) {
print p("Username already taken, Try again");
}

#As of now the else statement is running everytime and saving new user credentials even if a username is already taken
else {
open  my $fh, ">>", "password.txt" or die $!;
print $fh "$username:$hashpass\n";
print p("Your account has been created sucessfully");
close $fh;

}
print end_html();

Ответы [ 3 ]

4 голосов
/ 12 февраля 2012

Вы объявляете НОВУЮ переменную лексической области $nametaken внутри вашего цикла foreach, а точнее, внутри блока if {}: my $nametaken = $user;

Может иметь то же имя, что и переменная $nametaken, которая была у вас снаружи, но это совершенно другая переменная, с областью действия этого блока if - когда вы выходите из if, эта переменная полностью забывается. Какое бы значение вы ни присвоили, оно будет потеряно.

Подробнее о переменных в лексической области вы можете посмотреть здесь:

http://perldoc.perl.org/perlsub.html#Private-Variables-via-my%28%29


Чтобы решить вашу проблему тактически, вам просто нужно удалить объявление my из if: $nametaken=$user;

Чтобы сделать это правильно, в Perl, вам следует полностью переосмыслить свой подход к проблеме. Вы МОЖЕТЕ использовать цикл foreach, чтобы определить, есть ли значение в списке, но это определенно НЕ лучший (с точки зрения читабельности, а иногда даже с точки зрения производительности) метод Perl. Более идиоматический способ - использовать поиск по хешу:

my %users = map { ($_ => 1) } @users; # Create a hash with users being keys
if ($users{$username}) {
    print "$username already taken!\n";
}
3 голосов
/ 12 февраля 2012
my $nametaken = $user;

создает новую переменную с именем $nametaken, которая не имеет ничего общего с $nametaken, который вы объявили вне цикла.

2 голосов
/ 12 февраля 2012

Причина, по которой $nametaken не имеет значения вне цикла foreach, заключается в том, что он был лексически ограничен для определения только внутри foreach.


Всегда есть большечем один способ сделать это:

my ( $nametaken ) = grep { /$username/ } @users;

if ( $nametaken ) { ...  } else { ... }

или просто:

if ( grep { /$username/ } @users ) { ... } else { ... }

Обычно обычно менее шумно, когда в Perl меньше временных переменных.

...