【问题标题】:Passing an array into Perl subroutine将数组传递给 Perl 子例程
【发布时间】:2014-09-26 00:39:21
【问题描述】:

我有一个应该将数组作为输入的子例程,将其转换为 CSV,然后将其发布到 URL。到目前为止,这是我所得到的:

一个示例数组:

[   2823383062, 1411691539,   1411691541,        'outgoing',
    'SIP/fr',   'user@2000',  '2000',            'SIP/2000-000000a2',
    undef,      '6125551234', 'SIP/fr-000000a3', undef,
    undef,      8,            'Answered',        2,
    1,          'nada'
];

子程序:

sub send_http {
    my @http = @_;
    my $h    = LWP::UserAgent->new;
    $h->timeout(15);
    $h->agent(undef);

    my $testkey = "1234";
    my $apikey  = "4567";

    my $posting;
    foreach my $v ( \@http ) {
        if ( defined $v ) {
            $posting = join( ',', $posting, $v );
        } else {
            $posting = join( ',', $posting, "" );
        }
    }

    my $api_response = $h->post( 'http://url.com/v1/post.cfm',
        [ key => $testkey, method => 'pushCalls', rawdata => $posting ] );
}

原谅我做过的所有可怕的事情;这是我第一次使用 Perl,我还在学习各种东西。我的问题是我似乎无法从通过第一个数组变量声明(@http)传递给它的数组中获取值。我读过一些关于获取数组引用的内容,但不确定在哪里/如何这样做。任何帮助表示赞赏。

编辑: 这是整个脚本。它做了(或应该)两件事;将一些数据字符串发送到 TCP 套接字,而其他一些数据则被 POST 到 URL。感谢大家的帮助。

#!/usr/bin/perl
use EV;
use Asterisk::AMI;
use Net::Telnet;
use HTTP::Request::Common;
use LWP::UserAgent;
use strict;
use warnings;
use Data::Dumper;

my %call;

my $t = new Net::Telnet (
  Timeout => 10,
  Port => '1234',
  Telnetmode => 1
);

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

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

sub send_pos {
  my ($pos_string,$telnet) = @_;

  $telnet->open('127.0.0.1');
  printf $t $pos_string;
  $telnet->close()
}

sub send_http {
  my $http = shift; #@_;
  my $h = LWP::UserAgent->new;
    $h->timeout(15);
    $h->agent(undef);

  my $testkey = "1234";
  my $apikey = "5678";

  my $posting;
  foreach my $v ( @http ) {
    if ( defined $v ) {
      $posting = join(',', $posting,$v);
    } else {
      $posting = join(',', $posting,"");
    }
  }

  my $api_response = $h->post( 'http://url.com/v1/post.cfm',[key => $testkey,method => 'pushCalls',rawdata => $posting]);
}

sub eventhandler { 
  #   Default event handler, not used
  my ($ami, $event) = @_; 
  print 'Got Event: ',$event->{'Event'},"\r\n";
}

sub newchannel {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid'};

  if ( not exists $call{$unique_id} ) {
    my $this_call = $call{$unique_id};

  if ( (not defined $this_call->{'gravityfree'}[3]) ) {# || ($this_call->{'gravityfree'}[3] !~ /incoming|outgoing/) ) {
    if ( $event->{'Context'} =~ /from-trunk/ ) {
      #   Call is inbound
      $this_call->{'caller_name'} = $event->{'CallerIDName'};
      $this_call->{'caller_number'} = substr $event->{'CallerIDNum'}, -10;
      $this_call->{'dnis'} = substr $event->{'Exten'}, -10;
      $this_call->{'status'} = "remote";
      $this_call->{'holdstart'} = time();

      # Data required for Gravity Free
      $this_call->{'gravityfree'}[0] = int($event->{'Uniqueid'})+int(time());
      $this_call->{'gravityfree'}[3] = "incoming";
      $this_call->{'gravityfree'}[5] = $event->{'CallerIDName'};
      $this_call->{'gravityfree'}[6] = substr $event->{'CallerIDNum'}, -10;
      $this_call->{'gravityfree'}[7] =  $event->{'Channel'};
      $this_call->{'gravityfree'}[11] = substr $event->{'Exten'}, -10; 

      #  Can't remember why this is here:
      $call{$unique_id} = $this_call;

    } elsif ( $event->{'Context'} =~ /from-internal/ ) {
      #   Call is outbound
      #   Separate from calls to stations
      if( length($event->{'CallerIDNum'}) < length($event->{'Exten'}) ) {
          $this_call->{'status'} = "remote";
          #   Data required for Gravity Free
          $this_call->{'gravityfree'}[0] = int($event->{'Uniqueid'})+int(time());
          $this_call->{'gravityfree'}[9] = substr $event->{'Exten'}, -10;
          $this_call->{'gravityfree'}[3] = "outgoing";
          $this_call->{'gravityfree'}[6] = $event->{'CallerIDNum'};
          $this_call->{'gravityfree'}[5] = $event->{'CallerIDName'};

          $call{$unique_id} = $this_call;
      } elsif ( length($event->{'CallerIDNum'}) == length($event->{'Exten'}) ) {
        #   Call is station to station
        $this_call->{'status'} = "station-to-station";
      }
    }
  }
}
}

sub newexten {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid'};
  my $this_call = $call{$unique_id};

  #   Handles inbound calls only
  if ( defined $this_call->{'status'} && $this_call->{'status'} ne "station-to-station" ) {
    #   Call is not station to station
    #   Check if the DID has been defined
    if ( not defined $this_call->{'gravityfree'}[13] ) {
      if ( $event->{'Context'} eq 'ext-group' ) {
        # Data required for Gravity Free
        $this_call->{'gravityfree'}[13] = $event->{'Extension'};
      }
    }
  }
}

sub dialcheck {
  my ($ami, $event) = @_;
  my $unique_id = $event->{UniqueID};

  if ( exists $call{$unique_id} ) {
    my $this_call = $call{$unique_id};

    if ( defined $this_call->{'status'} && $this_call->{'status'} ne "station-to-station" ) {
      #   Call is not station to station
      if ( $event->{'SubEvent'} eq 'Begin' && $this_call->{'gravityfree'}[3] =~ "incoming" ) {
        #   Call is inbound
        $this_call->{'system_extension'} = $event->{'Dialstring'};
        $this_call->{'dest_uniqueid'}  = $event->{'DestUniqueID'};

        # Data required for Gravity Free
        $this_call->{'gravityfree'}[4] = $1 if $event->{'Channel'} =~ /(.+(?=\-\w+)).*/;

        #   Telnet data to Prodigy  
        my $sending = "R|$this_call->{'caller_name'}|$this_call->{'caller_number'}|$this_call->{'system_extension'}||$this_call->{'dnis'}|";
        send_pos($sending,$t);

        $this_call->{'status'}  = "ringing";
      } elsif ( $event->{SubEvent} eq 'Begin' && $this_call->{'gravityfree'}[3] =~ "outgoing" ) {
        #   Call is outbound
        #   Data required for Gravity Free
        $this_call->{'gravityfree'}[4] = $1 if $event->{'Destination'} =~ /(.+(?=\-\w+)).*/;
        $this_call->{'gravityfree'}[10] = $event->{'Destination'};
        $this_call->{'gravityfree'}[7] = $event->{'Channel'};
      }
    }
  }
}

sub outring {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid'};
  my $this_call = $call{$unique_id};

  if ( defined $this_call->{'status'} && $this_call->{'status'} ne "station-to-station" ) {
    #   Call is not station to station  
    if ( not defined $this_call->{'holdstart'} && $this_call->{'gravityfree'}[3] eq "outgoing" ) {
      #   Call is outbound
      $this_call->{'holdstart'} = time();
    }
  }
}

sub bridgecheck {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid1'};
  my $this_call = $call{$unique_id};

  if ( defined $this_call->{'status'} && $this_call->{'status'} ne "station-to-station" ) {
    #   Call is not station to station
    if ( $event->{'Bridgestate'} eq "Link" && length($event->{'CallerID2'}) <= 4 ) {
      #   Call is inbound
      $this_call->{'dest_uniqueid'}  = $event->{Uniqueid2};

      # Data required for Gravity Free
      $this_call->{'gravityfree'}[1] = time();
      $this_call->{'gravityfree'}[10] = $event->{Channel2};

      my $sending = "A|$this_call->{caller_name}|$this_call->{caller_number}|$event->{CallerID2}||$this_call->{dnis}|";
      send_pos($sending,$t);

      $this_call->{'status'}  = "answered";

    } elsif ( $event->{'Bridgestate'} eq "Link" && length($event->{'CallerID2'}) >= 4 ) {
      #   Call is outbound
        $this_call->{'gravityfree'}[1] = time();
        $this_call->{'gravityfree'}[13] = $this_call->{'gravityfree'}[1]-$this_call->{holdstart};
    }
  }
}


sub hangup {
  my ($ami, $event) = @_;
  my $unique_id = $event->{'Uniqueid'};
  my $this_call = $call{$unique_id};

  if ( defined $this_call->{'status'} && not defined $this_call->{'gravityfree'}[16] && $this_call->{'status'} ne "station-to-station" ) {
    #   Call is not station to station
    if ( $event->{'Cause-txt'} eq "Normal Clearing" ) {
      #   Call was hungup normally
      $this_call->{'dest_uniqueid'}  = $event->{Uniqueid};
      #   Call has ended, get date/time
      $this_call->{'gravityfree'}[2] = time();
      #   Mark call 'completed'
      $this_call->{'gravityfree'}[16] = 1;
      #   Set notes to nothing
      $this_call->{'gravityfree'}[17] = 'nada';

      if ( defined $this_call->{'gravityfree'}[3] && $this_call->{'gravityfree'}[3] eq "incoming") {
        #   Call was inbound
        if ( defined $this_call->{'gravityfree'}[1] ) {
          #   Call was answered
          $this_call->{'gravityfree'}[13] = $this_call->{'gravityfree'}[1]-$this_call->{holdstart};
          $this_call->{'gravityfree'}[14] = "Answered";
          $this_call->{'gravityfree'}[15] = $this_call->{'gravityfree'}[2]-$this_call->{'gravityfree'}[1];
          $this_call->{'gravityfree'}[8] = $event->{'ConnectedLineName'};
          $this_call->{'gravityfree'}[9] = substr $event->{'ConnectedLineNum'}, -10;

          #   POST data to gravity free
          send_http(\$this_call->{'gravityfree'});

        } else {
          #   Call was abandoned
          $this_call->{'gravityfree'}[14] = "Abandoned";
          $this_call->{'gravityfree'}[13] = $this_call->{'gravityfree'}[2]-$this_call->{holdstart};
          $this_call->{'gravityfree'}[15] = 0;

          #   POST data to gravity free
          send_http(\$this_call->{'gravityfree'});
        }

      } elsif ( defined $this_call->{'gravityfree'}[3] && $this_call->{'gravityfree'}[3] eq "outgoing" ) {
        #   Call is outbound
        if ( defined $this_call->{'gravityfree'}[1] ) {
          #   Call was bridged at some point
          $this_call->{'gravityfree'}[15] = $this_call->{'gravityfree'}[2]-$this_call->{'gravityfree'}[1];
          $this_call->{'gravityfree'}[14] = "Answered";

          #   POST data to gravity free
          send_http(\$this_call->{'gravityfree'});
        } else {
          #   Call was hung up before anyone answered
          $this_call->{'gravityfree'}[15] = 0;
          $this_call->{'gravityfree'}[14] = "Abandoned";
          $this_call->{'gravityfree'}[13] = $this_call->{'gravityfree'}[2]-$this_call->{holdstart};

          #   POST data to gravity free
          send_http(\$this_call->{'gravityfree'});
        }
      }
    }
  }
}

EV::loop

【问题讨论】:

    标签: arrays perl


    【解决方案1】:

    我不完全确定您要做什么,但一切都取决于您如何将数组传递给子例程。你有两个选择,要么将其作为数组传递:

    send_http(@array)
    

    或作为对数组的引用:

    send_http(\@array)
    

    正如其他人所指出的,您的数组已经是一个引用,因为您在方括号[ ] 中定义它。

    你想要哪一个取决于你到底在做什么,但语法不同。传递一个数组并遍历它:

    sub send_http {
    my @http = @_;
      foreach my $v (@http) {
          print "v is $v\n";
     }
    }
    my @aa=("cc","dd");
    send_http(@aa);
    

    传递一个引用并遍历它指向的数组:

    sub send_http {
     ## Remove the first value from the @_ array.
     my $http = shift @_;
     ## Dereference it to an array. You could also use @{$http}
     foreach my $v (@$http) {
          print "v is $v\n";
     }
    }
    
    my @aa=("cc","dd");
    send_http(\@aa);
    

    主要区别在于,当您使用 send_http(\@aa); 时,您传递的不是数组,因此您不能将其视为一个数组。相反,它是对数组的引用。类似的东西

    send_http(ARRAY(0x1d34030));
    

    所以,@_ 的内容只是一个引用,ARRAY(0x1d34030)。要将其视为一个数组,您需要取消引用它以获取它所指向的内容。

    【讨论】:

    • 使用\@array 来引用数组更为常见。构造 [@array] 实际上是对数组的副本的引用。
    • @GrantMcLean 这正是我在代码中使用它的原因。我在第一部分的示例中使用了[@array] 格式,只是因为这是 OP 使用的,我想让它保持熟悉。
    【解决方案2】:

    第一个问题,你从哪里得到你传递给子例程的数组? 我问是因为您的示例数组实际上是一个数组引用。

    即:

    @array = (1, 2, 3);  # This is an array
    $ref   = [1, 2, 3];  # This is an array reference
    

    如果要将数组引用传递给子例程,请将开头更改为:

    sub send_http {
    my $http = shift;
    

    接下来,让我们考虑如何迭代数组的元素。这是这样做的正确方法:

    foreach my $element ( @array ) { 
      # do stuff ...
    }
    

    当您对数组执行 \@ 时,实际上是在创建对数组的引用。因此,如果您确实将数组传递给您的子例程,您应该将循环更改为以下内容:

    foreach my $v ( @http ) {
    

    但是,如果您决定将数组作为引用传递,您可以取消引用指针并迭代其元素,如下所示:

    foreach my $v ( @$http ) {
    

    希望这会有所帮助!

    编辑:对于新上传的代码...

    您非常接近,但我们有几个小问题:

    $this_call->{'gravityfree'} 实际上已经是一个数组引用,我不确定为什么它允许您使用 $this_call->{'gravityfree'}[INDEX] 来处理数组元素,所以也许有人比我更有知识的人可以启发我们所有人。我会注意到,尊重数组的正确方法如下:

    \@{$this_call->{'gravityfree'}}
    

    无论如何,您可以简单地将引用传递给您的子例程,无需创建引用。那就是:

    send_http($this_call->{'gravityfree'});
    

    现在,在您的子程序内部,您有一个数组引用。您正在正确读取子例程参数,但您需要在 foreach 循环中取消引用该引用。像这样:

    foreach my $v ( @$http ) {
      # ... loop body
    }
    

    这有意义吗?如果有任何不清楚(或不起作用!),请告诉我

    【讨论】:

    • 好吧,这是有道理的。我开始认为我可能首先对如何构建数组有疑问。它实际上是一个哈希值,我一直通过为索引分配值来实现它,如下所示:$this_call-&gt;{'gravityfree'}[6];其中 $this_call 是一个哈希,gravityfree 是一个键。我在写这篇文章时感到畏缩,但我应该怎么做呢?谢谢!
    • @lorsungcu 只是为了确保您了解数据结构和引用之间的区别:$this_call 实际上是一个哈希引用,这就是您使用 -> 运算符访问元素的原因。 IE。 %hash{'key'} 用于访问哈希,$hash_ref-&gt;{'key'} 用于访问哈希引用。对于数组也是如此:@array[$index] 用于数组,$array_ref-&gt;[$index] 用于数组引用!现在我仍然不能 100% 确定你是如何构建阵列的,你能提供更多细节吗?对不起,我的困惑!
    • 谢谢,我有点理解;到目前为止,我一直在研究什么有效/我能快速找到什么。现在它不起作用,所有这些澄清都在下沉:) 我将编辑我的帖子并添加脚本的其余部分。
    • 我第一次看到 Perl 代码时不知道我在看什么,所以我完全可以理解。看到更新我会回复的!
    • 都在上面。再次感谢。
    【解决方案3】:

    因此,在您的 send_http 中,您收到的参数是 array_ref,它是标量变量,所以当您使用它时,您需要取消对正确类型的引用。

    注意:方括号是array_reference

    所以,请更改如下:

    my $http = shift;
    

    请使用它作为:

    foreach my $v ( @$http ) {
    

    例子:

    my $array_ref = [1,2,3];
    print "Reference: ", $array_ref,"\n";
    print "Array: ", @$array_ref,"\n";
    

    输出:

    Reference: ARRAY(0x7f8e1c004ee8)
    Array: 123
    

    【讨论】:

      猜你喜欢
      • 2021-03-09
      • 2012-05-30
      • 2013-12-24
      • 2017-04-20
      • 1970-01-01
      • 1970-01-01
      • 2016-09-07
      • 2011-08-06
      • 1970-01-01
      相关资源
      最近更新 更多