0

我的数据文件: votes.txt 由与以下内容相同的行组成:

VOTE 1168241980 Campaign:ssss_uk_01B Validity:during 
Choice:Tupele CONN:MIG00VU MSISDN:00088866655598 
GUID:A34-FDS87-FHDHDH-DHDHDHD0 Shortcode:63334

每个条目用空格分隔。我目前有 19 行的样本。

领域:

CONN:MIG00VU MSISDN:00088866655598 
GUID:A34-FDS87-FHDHDH-DHDHDHD0 Shortcode:63334

没有用于此练习。

#!/usr/bin/perl 

use warnings;
use strict;
use Switch;
use DBI();

#
# _voting.pl
#

# Connect to the database.
my $dbh = DBI->connect("DBI:mysql:database=sms_voting;host=localhost",
                    "sisisi", "*********",
                    {'RaiseError' => 1});

my $sth = $dbh->prepare("INSERT INTO voting 
(epoch, validity, choice, campaigns_id, candidates_id ) VALUES (?,?,?,?,?)");

open (LOGFILE, '/var/www/voting/votes.txt') or die("Could not open log file.");

my $errors = 0;
my $campaign_id = 0;
my $candidate_id = 0;

foreach my $line (<LOGFILE>) {  

    my ($vote, $epoch, $campaign, $validity, 
 $choice, $CONN, $MSISDN, $GUID, $Shortcode) = split(' ', $line);

# parse the field:value entries...
$campaign = substr $campaign, 8, 11, '';
$validity = substr $validity, 9, 6, ''; # during
$choice = substr $choice, 7, 10, ''; # Brown

# case statements to define correct foreign keys...
 switch ($campaign) {
        case ("ssss_uk_01B")    { $campaign_id = 1 } 
        case ("ssss_uk_01C")    { $campaign_id = 2 } 
        case ("ssss_uk_01D")    { $campaign_id = 3 } 
        case ("ssss_uk_01E")    { $campaign_id = 4 } 
        case ("ssss_uk_01F")    { $campaign_id = 5 } 
        case ("ssss_uk_01G")    { $campaign_id = 6 } 
}

switch ($choice) {
        case ("Brown")      { $candidate_id = 1 } 
        case ("Cameron")    { $candidate_id = 2 } 
        case ("Balls")      { $candidate_id = 3 } 
        case ("Green")      { $candidate_id = 4 } 
        case ("Boring")     { $candidate_id = 5 } 
        case ("Tupele")     { $candidate_id = 6 } 
}

if ($epoch && $validity && $choice && $campaign_id && $candidate_id ) {

    $sth->execute($epoch, $validity, $choice, $campaign_id, $candidate_id);
    # debug
    print "$epoch $validity $choice \n"; # 1161048980 during Green
    next;
} 

$errors++;
 }

close (LOGFILE);

# debug
print qq(errors=$errors\n);

对于 foreach 的每个循环,$campaign 和 $choice 变量都通过 switch 语句运行,以定义候选 ID 和活动 ID 数字。这些外键将分别映射到候选人和竞选表。

有关数据库模型,请参见:http ://acookson.org/wp-content/themes/cookie_23112012/img/sms_voting.png。

IE

INSERT INTO voting (epoch, validity, choice, campaigns_id, candidates_id ) 
VALUES (1161048980,'during','Brown', 1, 1),
(1161048980,'during','Tupele', 3, 5), ... etc

在 votes.txt 中检测到的任何空值都会导致 $errors 变量增加。

该脚本似乎成功循环通过 votes.txt 但未能初始化:$campaign_id 和 $candidate_id 变量。完成后,errors=19 被打印到终端;我的样本数据 votes.txt 中的总行数;这意味着该文件中的每一行都未能插入到数据库中。

mysql> select * from voting;
Empty set (0.00 sec)

证实了这一点。

该脚本没有报告语法错误;因此它的级别更低。没有开关就可以正常工作;因此,这在一定程度上缩小了范围。但是我看不到开关的问题,所以在这里寻求建议。

4

2 回答 2

0

不确定您的问题是什么,但这里有一些关于您的 Switch 语句和其他代码的指针。

据我所知,该use Switch功能/模块已在 perl v5.10.1 中替换为该given/when功能,现在已弃用。就个人而言,我一直觉得这些陈述有点奇怪和不可靠。并且无论如何都不是不可替代的,因为 perl 是一种如此灵活的语言。

在您的情况下,我会建议使用哈希查找:

my %camp = ("ssss_uk_01B" => 1,
            "ssss_uk_01C" => 2,
            ...);
my %cand = ("Brown"       => 1,
            "Cameron"     => 2,
            ...);

$campaign_id  = $camp{$campaign};
$candidate_id = $cand{$choice}

如果需要提供默认值,可以使用defined-or赋值运算符:

$campaign_id //= "default value here";

你的substr作业有点错误。首先,您使用所有四个参数,在 perldoc 中是这样描述的:

substr EXPR,OFFSET,LENGTH,REPLACEMENT

这意味着您将匹配项替换''为空字符串。这会影响变量本身,并且会删除您想要的数据(如果单独保留)。您的情况也不需要长度,因为它是您所追求的字符串的结尾。最后,您因使用substr语句的返回值而得救。

最后,当我尝试你的作业时,我在你的第一个作业中遇到了一次性错误($campaign)。输出是:ssss_uk_01,并且您期望ssss_uk_01

substr正确使用该功能,您应该使用:

$campaign = substr $campaign, 9;
$validity = substr $validity, 9;
$choice   = substr $choice, 7;
于 2012-12-01T14:16:04.567 回答
0

我同意 TLP 关于将哈希用于查找表的建议。但在实际应用程序中,这些查找表应该使用数据库查找来填充,以避免在其他表中的数据发生更改时需要更改应用程序。

我也倾向于不太信任日志中数据的格式。使用 split 减少了知道标签+冒号大小的确切长度的需要。沿着这条线,我还建议在将数据用作查找哈希中的键之前对其进行规范化。在此示例中,我只是将其全部设为小写。

当您使用警告时,您不妨使用警告功能来发现错误情况。在实际应用程序中,您可能会在电子邮件警报系统中点击警告,这样您就可以随时知道无人值守的软件何时出现问题。

在进行文件操作时,or+die 习惯用法是一种极好的做法。但是,如果您包含 $OS_ERROR(又名 $!),即使是用于打印,当这些死亡发生时它会提供更多信息。通过这种方式,您将知道权限被拒绝、不存在或磁盘已满等之间的区别。

这些建议涉及编写可维护和有弹性的程序的问题。但我个人认为代码的美感也有助于可维护性。当您在一两年后打开此程序以进行改进或修复错误时,有意义的命名约定和代码格式会产生很大的不同。我更喜欢创建没有不必要混乱的代码,例如说明显而易见的注释或使用注释来删除代码块。

保持良好的工作。世界需要更多的软件自动化。

#!/usr/bin/perl

use strict;
use warnings;
use DBI;

#
# _voting.pl
#
my $logfile = '/var/www/voting/votes.txt';

my $errors = 0;

my %campaign_id_for = (
    'ssss_uk_01b' => 1,
    'ssss_uk_01c' => 2,
    'ssss_uk_01d' => 3,
    'ssss_uk_01e' => 4,
    'ssss_uk_01f' => 5,
    'ssss_uk_01g' => 6,
);

my %candidate_id_for = (
    'brown'   => 1,
    'cameron' => 2,
    'balls'   => 3,
    'green'   => 4,
    'boring'  => 5,
    'tupele'  => 6,
);

my $dbh = DBI->connect( 
    'DBI:mysql:database=sms_voting;host=localhost',
    'sisisi', 
    '*********', 
    { 'RaiseError' => 1 } 
);

my $sth = $dbh->prepare(q{
    INSERT INTO voting (
        epoch,
        validity,
        choice,
        campaigns_id,
        candidates_id
    ) VALUES (
        ?,
        ?,
        ?,
        ?,
        ?
    )
});

my $fh;

open $fh, '<', $logfile
    or die "open $logfile: $!";

LINE:
for my $line (<$fh>) {

    my ($vote, $epoch,  $campaign, $validity, $choice,
        $CONN, $MSISDN, $GUID,     $Shortcode
    ) = split /\s+/, $line;

    ($campaign) = reverse split /:/, $campaign;
    ($validity) = reverse split /:/, $validity;
    ($choice)   = reverse split /:/, $choice;

    my $campaign_id  = $campaign_id_for{ lc $campaign };
    my $candidate_id = $candidate_id_for{ lc $choice };

    if ( $epoch && $validity && $choice && $campaign_id && $candidate_id ) {

        $sth->execute(
            $epoch,
            $validity,
            $choice,
            $campaign_id,
            $candidate_id
        );

        print "$epoch $validity $choice\n"
            or die "print: $!";

        next LINE;
    }
    else {

        warn "failed to parse: $line\n";
        $errors++;
    }
}

close $fh
    or die "close $logfile: $!";

# debug
print "error count: $errors\n"
    or die "print: $!";
于 2012-12-01T15:52:48.400 回答