【问题标题】:string parsing in perlperl 中的字符串解析
【发布时间】:2015-03-11 19:39:12
【问题描述】:

我需要一些关于 perl 中字符串解析的帮助。 我有一个响应如下内容的 http 服务器:

<html>
<head><title></title></head><body>
T:17.10;H:32.10
</body></html>

我需要捕捉这两个数字(在示例 17.10 和 32.10 中)并将它们放入两个变量中,我将用于执行一些 if...then...else 循环。

我在字符串操作和正则表达式方面不是那么专家,目前我正在尝试这样做:

my $url = 'http://192.168.25.9';
my $content = get $url;
die "Couldn't get $url" unless defined $content;
my @lines = split /\n/, $content;
$content2 = $lines[2];
$content2 =~ tr/T://d;
$content2 =~ tr/H://d;
my @lines2 = split /;/, $content2;
$tem = $lines2[0];
$hum = $lines2[1];

$tem =~ m{(\d+\.\d+)};
$hum =~ m{(\d+\.\d+)};

但是当我打印出该行时,我看到了一些奇怪的东西:缺少字符、行中有空格等。 看来我有一些奇怪的隐形字符会造成混乱。

你能建议我一个更好的方法让两个数字变量中的两个数字吗?

谢谢 法比奥

【问题讨论】:

  • 您正在打印哪些变量,您看到了什么?使用Data::Dumper 显示变量的内容。
  • 你是如何获得 html 的? get 来自哪个模块。

标签: string perl parsing http


【解决方案1】:

一个完整的解决方案,避免使用 REGEX 解析 HTML(参考:RegEx match open tags except XHTML self-contained tags ) :

use strict; use warnings;

# base perl module to fetch HTML
use LWP::UserAgent;
# base perl module to parse HTML
use HTML::TreeBuilder;

# fetching part
my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET => "http://192.168.25.9");
my $res = $ua->request($req);
die $res->status_line, "\n" unless $res->is_success;

# parsing part
my $tree = HTML::TreeBuilder->new();
# get text from HTML
my $out = $tree->parse($res->decoded_content)->format;
# extract the expected string from the text output
if ($out =~ /^\s*T:(\d{2}\.\d{2});H:(\d{2}\.\d{2}).*/) {
    print join "\n", $1, $2;
}

输出:

17.10
32.10

【讨论】:

  • 我认为涉及HTML::TreeBuilder 没有任何意义——当然不仅仅是为了格式化HTML。使用decoded_content 而不是content 也是明智之举,因为您不知道 HTTP 内容是否被压缩。
【解决方案2】:

对于此类请求,您可以这样做:

my ($t, $h) = map { (/T:(\d+|\d+.\d+);H:(\d+|\d+.\d+)/)?($1, $2):() } @req;
print "$t, $h\n", $t * $h;

输出:

17.10, 32.10
548.91

@req 是一个数组,其中包含接收到的请求的 chomped 字符串

【讨论】:

  • 这个解决方案对我来说似乎很好,我不明白反对意见。其他解决方案会进行大量不必要的工作来格式化或去除 HTML,除非您想确保所需的文本是 &lt;body&gt; 元素的唯一内容,否则这是完全没有必要的,而它们都没有这样做。不过,您的正则表达式有点幼稚,因为我认为这些数值很有可能看起来像 123.42.8896,甚至是 42,而您的模式与这些都不匹配。
  • 感谢鲍罗丁的支持。同意你的cmets。固定正则表达式。也许现在它更灵活了。
【解决方案3】:

出于您的目的,这就是您所需要的:

my ($tem, $hum) = $content =~ /T:(\d{2}\.\d{2});H:(\d{2}\.\d{2})/;

如果您需要更一般的解析(例如,支持温度或湿度 >= 100、单个数字值等...):

my ($tem, $hum) = $content =~ /T:(\d+(?:\.\d+)?);H:(\d+(?:\.\d+)?)/;

【讨论】:

  • 我认为不需要删除 HTML 标记。数据要么存在,要么不存在,尽管我猜在某个属性的值中找到错误匹配的可能性很小。
  • 没错,他这里并没有真正解析html。答案归结为一行:my ($tem, $hum) = $content =~ /T:(\d{2}.\d{2});H:(\d{2}.\d{2})/;
猜你喜欢
  • 2014-07-19
  • 2019-05-07
  • 2021-06-17
  • 2013-06-22
  • 1970-01-01
  • 2013-02-04
  • 2017-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多