Tcl Expect:错误可以';“我不读”;知识产权:没有这样的变量

Tcl Expect:错误可以';“我不读”;知识产权:没有这样的变量,tcl,expect,Tcl,Expect,我是expect/TCL的新手,正在尝试解析输出如下内容的HTML页面: <li><p>Timestamp: Wed, 14 Nov 2012 16:37:50 -0800 <li><p>Your IP address: 202.76.243.10</p></li> <li><p class="XXX_no_wrap_overflow_hidden">Requested URL: /</p>

我是expect/TCL的新手,正在尝试解析输出如下内容的HTML页面:

<li><p>Timestamp: Wed, 14 Nov 2012 16:37:50 -0800
<li><p>Your IP address: 202.76.243.10</p></li>
<li><p class="XXX_no_wrap_overflow_hidden">Requested URL: /</p></li>
<li><p>Error reference number: 1003</p></li>
<li><p>Server ID: FL_23F7</p></li>
<li><p>Process ID: PID_1352939870.809-1-428432242</p></li>
<li><p>User-Agent: </p></li>
时间戳:2012年11月14日星期三16:37:50-0800
  • 您的IP地址:202.76.243.10

  • 请求的URL:/

  • 错误参考号:1003

  • 服务器ID:FL_23F7

  • 过程ID:PID_1352939870.809-1-428432242

  • 用户代理:

  • 我的剧本在下面。我能够获取我无法解析的网页,该网页的“Your IP address:”行给了我错误:

    #!/usr/bin/expect -f
    set timeout -1
    spawn telnet www.whatismyip.com 80
    send "GET /\r\n"
    expect
    set output $expect_out(buffer)
    foreach line [split $output \n] {
            regexp {.*<li><p>Your IP Address Is:.*?(\d+\.\d+\.\d+\.\d+)} $line ip
            if {[string length ${ip}]} {
                    puts $ip
        }
    }
    
    #/usr/bin/expect-f
    设置超时-1
    spawn telnet www.whatismyip.com 80
    发送“GET/\r\n”
    期待
    设置输出$expect\u out(缓冲区)
    foreach行[拆分$output\n]{
    regexp{.*
  • 您的IP地址是:.*(\d+\.\d+\.\d+\.\d+}$line IP 如果{[string length${ip}]}{ 卖出$ip } }
  • 错误是:

        Connection closed by foreign host.
    can't read "ip": no such variable
        while executing
    "string length ${ip}"
        ("foreach" body line 3)
        invoked from within
    "foreach line [split $output \n] {
            regexp {.*<li><p>Your IP Address Is:.*?(\d+\.\d+\.\d+\.\d+)} $line ip
            if {[string length ${ip}]} {
     ..."
        (file "./t4" line 7)
    
    连接已被外部主机关闭。
    无法读取“ip”:没有此类变量
    执行时
    “字符串长度${ip}”
    (“foreach”正文第3行)
    从内部调用
    “foreach行[拆分$output\n]{
    regexp{.*
  • 您的IP地址是:.*(\d+\.\d+\.\d+\.\d+}$line IP 如果{[string length${ip}]}{ ..." (文件“/t4”第7行)

  • 是否有我出错的指针?

    正则表达式不匹配,因此未分配变量。您应该检查
    regexp
    的结果以查看匹配是否成功;如果未使用
    -all
    选项来
    regexp
    ,则可以将其视为布尔值。尝试以下操作:

    foreach line [split $output \n] {
        if {[regexp {<li><p>Your IP Address Is:.*?(\d+\.\d+\.\d+\.\d+)(?!\d)} $line -> ip]} {
            puts $ip
        }
    }
    
    foreach行[拆分$output\n]{
    如果{[regexp{
  • 您的IP地址是:.*(\d+\.\d+\.\d+\.\d+(?!\d)}$line->IP]}{ 卖出$ip } }
  • ->
    确实是一个(奇怪的!)变量名,它将保存整个匹配的字符串;我们对它不感兴趣(只是插入的部分),所以我们使用非字母形式的助记符来表示“这就要到那里了”(与
    ip
    变量的子匹配)。

    您的行包含“地址”(小写)但是您正在尝试匹配“地址”(大写)。添加
    regexp命令的-nocase选项。此外,Tcl正则表达式不能具有混合贪婪性——第一个量词确定整个表达式是贪婪的还是非贪婪的(我现在找不到记录在哪里)


    如果您的最终目标是获得主机的外部IP,那么请使用API解决方案,例如exip.org提供的解决方案:

    #!/usr/bin/env tclsh
    
    set api http://api-nyc01.exip.org/?call=ip
    if {[catch {exec curl --silent $api} output]} {
        puts "Failed to acquire external IP"
    } else {
        puts "My external IP is $output"
    }
    

    请访问他们的网站了解更多信息,特别是如果您居住在美国境外。此解决方案需要
    curl
    ,您可能需要安装。

    谢谢,它可以工作,但IP值仅被其最后一个字符值截断。我的代码是如果{[regexp{
  • 您的IP地址:.*(\d+.\d+.\d+.\d+.\d+}$line->IP]}{如果标记是
  • 你的IP地址:202.76.243.10

  • 我得到的结果是$IP为202.76.243.1-最后的0被忽略了啊!你已经被不贪婪咬到了。由于非常糟糕的技术原因,RE中的所有量词都是非贪婪的:你需要确保RE被适当地锚定,这是由在RE结尾处加入一个负面展望(
    (?!\d)
    :“下一位没有数字”)“真的很糟糕的技术原因”这与Tcl使用自动机理论的重新引擎而不是基于堆栈的PCRE及相关系统有关。实现这一点的代码绝对不是琐碎和可怕的复杂。我自己,我总是尝试编写完全贪婪的重新引擎;很久以前我就是这样被教导的,他们的行为(相对而言)很容易理解。最初的RE是您提供的,但是由于您并不真正需要它,所以去掉了前面的
    *
    ,但这迫使RE的其余部分被解释为贪婪的…我没有发现。哦,好吧!顺便说一句,试着使用http包:
    包需要http;设置tok[http::geturl www.whatismyip.com];如果{[regexp{
  • 您的IP地址是:.*(\d+\.\d+\.\d+\.\d+.\d+(!\d)}[http::data$tok]>IP]}{put$IP};http::cleanup$tok
  • 与我在这里得到的值相同-如前所述,ip值被最后一个字符截断-如果标记值是ip地址:202.76.243.10

    我得到的'put$ip'为202.76.243.1-最后的0被忽略
    #!/usr/bin/env tclsh
    
    set api http://api-nyc01.exip.org/?call=ip
    if {[catch {exec curl --silent $api} output]} {
        puts "Failed to acquire external IP"
    } else {
        puts "My external IP is $output"
    }