使用sed根据多个参数从html中提取整数

使用sed根据多个参数从html中提取整数,html,bash,parsing,sed,Html,Bash,Parsing,Sed,首先,让我说: 我知道注册html被认为是一种糟糕的方法,但如果chuck norris可以,为什么我不能呢?;) 我要分析此html页面: 基于三个参数。我试过:(谢谢你pixellany) 返回228344而不是228338 我试着:(谢谢你加倍努力) 返回228343而不是228338 预期结果是228338,因为它是第一个数字,前面是“downloadstitle.php\?id\=”,后面是“希伯来语”和“尽管” 我缺少什么?Perl解决方案: perl -nE ' @fiel

首先,让我说:
我知道注册html被认为是一种糟糕的方法,但如果chuck norris可以,为什么我不能呢?;)
我要分析此html页面:
基于三个参数。我试过:(谢谢你pixellany)

返回228344而不是228338
我试着:(谢谢你加倍努力)

返回228343而不是228338 预期结果是228338,因为它是第一个数字,前面是“downloadstitle.php\?id\=”,后面是“希伯来语”和“尽管”
我缺少什么?

Perl解决方案:

perl -nE '
    @fields = split /downloadsubtitle\.php\?id=([0-9]+)/;
    for (1 .. $#fields) {
        next unless $_ % 2;
        say $fields[$_] if $fields[$_ + 1] =~ /hebrew.*DESPiTE/;
    }
' unAifctF.html

它是如何工作的?它在downloadstitle.php?id=XXX上拆分一行,同时将数字保持在中间。然后,它打印一个数字,如果它后面的字符串直到下一个
downloadsubtitle…
包含
希伯来语
,然后是
,尽管

问题是
*
是一个贪婪的操作符,因此它将尽可能多地匹配,导致它不是在第一个可能的匹配上停止,而是在最后一个可能的匹配上停止。因此,您可能应该更改它试图匹配的内容。问题是,您希望它匹配除另一个“downloadstitle.php?id=”之外的任何内容,这在
sed
中很困难。您可以创建一个更复杂的sed脚本,也可以使用一个简单的变通方法,假设链接和title=)之间没有任何
s)

如果您想要一个合适的脚本:

#!/bin/sed -nf

: next
$! { N; b next }
s/\n//g

s/downloadsubtitle\.php?id=\([0-9][0-9]*\)/\
\1/

: loop
s/^[^\n]*\n//

h
s/\([0-9]*\).*/\1/
x

s/downloadsubtitle\.php?id=\([0-9][0-9]*\)/\
\1/
/^[^\n]*hebrew[^\n]*DESPiTE/ { g; p; q }
/^[0-9]*/ b loop
该脚本首先将整个文件加载到模式空间(即工作缓冲区)。它在前两行中执行此操作。第一行用
命令声明一个名为
next
的标签。第二行使用
N
命令将input中的下一行追加到模式空间中,然后跳回
next
标签,但这两个命令仅在我们尚未读取最后一行时执行。第三行删除所有换行符

现在,我们将第一次出现的
downloadstitle\.php?id=[0-9][0-9]*
替换为换行符(由反斜杠和实际的新行表示)和id号

创建一个新的标签
循环
,之后我们要做的第一件事是删除第一个换行符之前的所有内容(因此我们删除id之前的所有内容)

现在我们有了一系列命令,可以提取数字并将其存储到保持空间(一个辅助缓冲区)中。我们首先使用
h
命令将整个模式空间复制到保持空间,然后删除数字后面的所有内容,然后用
x
交换保持空间和模式空间的内容。现在,保留空间包含数字,模式空间恢复为其值

为了防止贪婪的搜索,我们将在下一次出现
downloadstitle\.php?id=[0-9][0-9]*
之前放置一个换行字符。我们也可以只留下ID号,因为换行符将指示我们找到了字符串的其余部分

现在是搜索部分。总而言之,我们在保留空间中有实际的ID,模式空间的第一行是我们要搜索文本的地方。因此,我们使用搜索表达式,从缓冲区的开始搜索字符串
希伯来语
尽管
,它们彼此之间或从缓冲区的开始处没有换行符。因此,我们只搜索了第一行

如果找到匹配项,我们使用
g
从保留空间获取ID,
p
打印它,然后使用
q
退出

如果没有找到匹配项,我们只需跳回
循环
标签,然后搜索下一个发生的情况。跳转之前的条件是防止无限循环。如果没有什么可搜索的,它就会退出

希望这有帮助=)

这可能对您有用(GNU-sed):

解释:

  • /[\x00\x01\x02]/q1
    检查行中是否包含分隔符,如果包含分隔符,请使用错误代码中止
    1
  • /hebrew/!Bs//\x01/
    检查行中是否包含
    希伯来语
    ,如果没有跳出,则将单词
    希伯来语
    翻译为单个字符
    \x01
  • /尽管如此/!Bs//\x02/
    检查行中是否包含
    尽管
    如果未跳出,则将单词
    尽管
    翻译为单个字符
    \x02
  • /downloadstitle.php?id=/!Bs//\x00/
    检查行中是否包含
    downloadstitle.php?id=
    如果没有跳出,则将单词
    downloadstitle.php?id=
    翻译为单个字符
    \x00
  • s/*\x00\([0-9]\+\)[^\x00\x01\x02]*\x01[^\x00\x01\x02]*\x02.*/\1/p
    打印出所需的数字

我想放一个变量而不是“尽管”,比如:perl-nE'@fields=split/downloadstitle\.php\?id=([0-9]+)/;对于(1..$#fields){next除非$%2;如果$fields[$#+1]=~/hebrew.*$var/;}'unAifctF.html,我很累,但它不起作用。我需要转义它吗?@buntuser:如果变量可能包含特殊字符,您应该引用它:
/hebrew.*\Q$var\E/
我尝试过/hebrew.*\Q$var\E/和-/\Q$var1.*\Q$var\E/都不返回任何内容。如果返回原始,我会得到id(数字),当然$var将包含字母或数字。没有特殊字符。@buntuser:是的。单引号实际上中断了带引号的字符串,让shell插入变量值。
perl -nE '
    @fields = split /downloadsubtitle\.php\?id=([0-9]+)/;
    for (1 .. $#fields) {
        next unless $_ % 2;
        say $fields[$_] if $fields[$_ + 1] =~ /hebrew.*DESPiTE/;
    }
' unAifctF.html
sed -nr 's/.*downloadsubtitle.php\?id\=([0-9]+)[^?]*hebrew[^?]*DESPiTE.*/\1/p'
#!/bin/sed -nf

: next
$! { N; b next }
s/\n//g

s/downloadsubtitle\.php?id=\([0-9][0-9]*\)/\
\1/

: loop
s/^[^\n]*\n//

h
s/\([0-9]*\).*/\1/
x

s/downloadsubtitle\.php?id=\([0-9][0-9]*\)/\
\1/
/^[^\n]*hebrew[^\n]*DESPiTE/ { g; p; q }
/^[0-9]*/ b loop
sed -n '/[\x00\x01\x02]/q1;/hebrew/!b;s//\x01/;/DESPiTE/!b;s//\x02/;/downloadsubtitle.php?id=/!b;s//\x00/;s/.*\x00\([0-9]\+\)[^\x00\x01\x02]*\x01[^\x00\x01\x02]*\x02.*/\1/p' file