Проблемы сравнения переменных, назначенных в выражении foreach

Я работал над файлом 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 ответа

Решение

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

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

Вы можете увидеть более подробную информацию о лексически ограниченных переменных здесь:

http://perldoc.perl.org/perlsub.html


Чтобы тактически решить вашу проблему, вам просто нужно удалить 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";
}
my $nametaken = $user;

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

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


Всегда есть несколько способов сделать это:

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

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

или просто:

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

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

Другие вопросы по тегам