【问题标题】:Having trouble with hashes; first time Perl questions哈希有问题;第一次 Perl 问题
【发布时间】:2014-07-16 20:43:51
【问题描述】:

如果这个问题太含糊,我真的很抱歉;我会尽力尝试总结我的问题。这是我第一次使用 Perl,我想我已经接近了。

我有一个哈希值,用于存储从 Asterisk 收到的呼叫信息。

每个调用都应该在哈希中有一个条目,键是唯一的 ID(我知道这可能是不好的做法,但键会在脚本结束时被销毁,所以我不担心重复)。

当我从 Asterisk 获取数据时,我需要不断地将新数据附加到哈希元素,然后在某些时候将结果打印到 TCP 套接字。

这就是我所拥有的。我的问题是我似乎无法将新数据附加到同一个哈希键。

请原谅我的业余爱好;任何有关格式化/最佳实践/任何事情的帮助都将不胜感激!

use Asterisk::AMI;
use IO::Socket;

use strict;
use warnings;

use Data::Dumper;

my %call;

my $sock = new IO::Socket::INET(
  PeerAddr => '127.0.0.1',
  PeerPort => '1234',
  Proto    => 'tcp',
);

die "Could not create socket: $!\n" unless $sock;

my $astman = Asterisk::AMI->new(
  PeerAddr => '127.0.0.1',
  PeerPort => '5038',
  Username => 'user',
  Secret   => 'secret',
  Events   => 'on',
  Handlers => {
    #default    => \&eventhandler,
    Dial       => \&ringcheck,
    Bridge     => \&bridgecheck,
    Newchannel => \&newchannel
  }
);

die "Unable to connect to asterisk" unless ($astman);

# Default event handler
sub eventhandler {
  my ($ami, $event) = @_;

  print 'Got Event: ', $event->{'Event'}, "\r\n";
}

sub newchannel {
  my ($ami, $event) = @_;

  if ($event->{'Context'} eq "from-trunk") {
    $call = $event->{'Uniqueid'} => {
      caller_name   => $event->{'CallerIDName'},
      caller_number => $event->{'CallerIDNum'},
      dnis          => $event->{'Exten'}
    };
  }
}

sub ringcheck {
  my ($ami, $event) = @_;

  if ($event->{'SubEvent'} eq "Begin") {
    $call = $event->{'UniqueID'} => {
      system_extension => $event->{'Dialstring'},
      dest_uniqueid    => $event->{'DestUniqueID'}
    };
    print $sock "R|", $call{ $event->{'UniqueID'} }{'caller_name'}, "|",
        $call{ $event->{'UniqueID'} }{'caller_number'},    "|",
        $call{ $event->{'UniqueID'} }{'system_extension'}, "||",
        $call{ $event->{'UniqueID'} }{'dnis'},             "\r\n";
  }
}

sub bridgecheck {
  my ($ami, $event) = @_;

  if ($event->{'Bridgestate'} eq "Link") {
    # Call has started
    print $sock "A|", $call{ $event->{'UniqueID'} }{'caller_name'}, "|",
        $call{ $event->{'UniqueID'} }{'caller_number'},    "|",
        $call{ $event->{'UniqueID'} }{'system_extension'}, "||",
        $call{ $event->{'UniqueID'} }{'dnis'},             "\r\n";
  }
  elsif ($event->{'Bridgestate'} eq "Unlink") {
    # Call has ended
  }
}

EV::loop

需要明确的是,问题是我应该如何将新数据(例如在 ringcheck 子例程中)附加到在 newchannel 子例程中创建的 %call 哈希中?

【问题讨论】:

  • 你能把它变成一个更简单的例子吗?对于不了解 Asterisk 的人来说,现在的编写方式很难理解(这甚至与您所询问的内容无关)。
  • => 仅表示 , (除了它在其 LHS 上自动引用裸词)。我不知道你在做什么,但$call = $event->{'UniqueID'} => { ... }; 是错误的。事实上,这是一个警告。如果您告诉我们您遇到了错误,那就太好了。
  • @daotoad:这与 OP 已有的有什么不同?
  • @Borodin,主要区别在于它将内容列表与分隔符分开。 OP 的版本将分隔符(语句和字段)与字段内容混合在一起。 printf STATEMENT/STATEMENT_DELIMITER, join FIELD_DELIMITER, LIST_OF_FIELDS;。对于更高级的 perl 用户,我可能会添加一个映射来进行重复的 $call{} 哈希查找。 map { defined $cdr{$_} ? $cdr{$_} : $_ } 'A', 'caller_name', 'caller_number' ...; 使用qw// 也可以很好,但是由于我们需要在列表中使用一个空字符串,它会变得很混乱,尤其是当您不能在示例中使用换行符时。
  • @daotoad:你没有理解我的意思。也许您发布的代码中有更多的布局空白,但它已被布局引擎吞噬​​。除了这样的空格之外,您的替代语句完全匹配 OP 在其子例程中的print 语句bridgecheck

标签: perl hash


【解决方案1】:

由于您没有声明$call,因此您一定收到了来自use strict 的错误消息。如果您告诉我们,那会很有帮助。

  • 请使用最少的缩进:通常四个空格或更少,我使用两个。大缩进使代码难以理解

  • 即使在 Windows 上,也不要使用 "\r\n" 终止输出行。 Perl 处理所有这些,您应该在任何平台上打印"\n" 换行

  • 哈希%call 是一个完全独立于标量$call 的变量,因此分配给$call 根本不会影响您的哈希。如果 strict 已就位,您会看到错误,因为尚未定义 $call

  • 要分配给哈希元素,请使用$hash{$key}。把它想象成一个数组元素,但不是整数,而是哈希元素用字符串索引。如果要使用常量作为哈希键,可以省略引号,所以$call{'caller_name'}$call{caller_name} 相同

  • 1234563它。您可以使用哈希引用 $call{$unique_id} 做同样的事情

我已将您的代码更改为可行的,或者至少可以帮助您。我使用printf 将格式与数据分开,使其更具可读性。

sub ringcheck {
  my ($ami, $event) = @_;

  if ($event->{SubEvent} eq 'Begin') {

    my $unique_id = $event->{UniqueID};
    my $this_call = $call{$unique_id};

    $this_call->{system_extension} = $event->{Dialstring};
    $this_call->{dest_uniqueid}    = $event->{DestUniqueID};

    printf $sock "R|%s|%s|%s||%s\n",
        $this_call->{caller_name},
        $this_call->{caller_number},
        $this_call->{system_extension},
        $this_call->{dnis};
  }
}

【讨论】:

  • 有时,就像使用套接字一样,使用"\r\n" 作为终止符可能是有意义的。了解 PerlIO 的编码层如何更改行尾是一件好事。值得注意的层是:crlf,它是 Windows 系统上文件的默认值,:bytes 将文件作为八位字节流读取,:perlio 套接字的默认值,:unix 的高度缓冲版本,然后是 ':raw ' 这对于读取二进制文件很有用。有关详细信息,请参阅perldoc.perl.org/PerlIO.html
【解决方案2】:

您使用了错误的运算符进行赋值。 =>, 的同义词,具有引用其左侧操作数的附加效果(除非它是一个变量。)

我对 Asterisk 一无所知,但您可能想要:

$event->{'UniqueID'} = {
      system_extension => $event->{'Dialstring'},
      dest_uniqueid => $event->{'DestUniqueID'}
};

不过,我不确定你想用 $call 做什么。

【讨论】:

    猜你喜欢
    • 2011-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多