2012-10-17 60 views
1

首先,讓我這樣說:
我知道regx'ing html被認爲是一個壞的方法,但如果查克norris可以,爲什麼我不能? ;)
我想解析這個html頁面:http://pastebin.com/unAifctF
基於三個參數。我想:(謝謝pixellany)從html根據多個參數提取整數與sed

sed -n '/hebrew/{/DESPiTE/s/downloadsubtitle.php?id=/XXX/1};s/.*XXX\([0-9]*\).*/\1/p' 

返回的228344,而不是228338
我試圖:(謝謝doubleDown)

sed -nr 's/.*downloadsubtitle.php\?id\=([0-9]+).*hebrew.*DESPiTE.*/\1/p' 

返回的228343,而不是228338 該預期的結果228338,因爲它是第一個以「downloadsubtitle.php \?id \ =」開頭的數字,後面跟着「希伯來語」和「DESPiTE」
我錯過了什麼?

回答

1

這可能爲你工作(GNU SED):

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 

Explanantion:

  • /[\x00\x01\x02]/q1檢查行包含分隔符,如果是這樣,錯誤中止代碼1
  • /hebrew/!b;s//\x01/檢查行是否包含hebrew如果n OT擺脫困境,如果要是行包含DESPiTEhebrew所以譯成單個字符\x01
  • /DESPiTE/!b;s//\x02/檢查,如果不擺脫困境,如果是這樣的話DESPiTE譯成單個字符\x02
  • /downloadsubtitle.php?id=/!b;s//\x00/檢查,如果行包含downloadsubtitle.php?id=如果不保釋,如果有的話將downloadsubtitle.php?id=這個詞翻譯成單個字符\x00
  • s/.*\x00\([0-9]\+\)[^\x00\x01\x02]*\x01[^\x00\x01\x02]*\x02.*/\1/p打印出想要的數字。
+0

potong - 您的解決方案就像一個魅力!謝謝 – buntuser

1

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 

它是如何工作的?它在downloadsubtitle.php?id=XXX上分開一行,同時保持兩者之間的數字。然後,它打印一個數字,如果跟在其後的字符串包含hebrew,然後是DESPiTE

+0

魔法!非常感謝! – buntuser

+0

我想把一個變量,而不是「DESPITE」,如下所示:perl -nE' @fields = split /downloadsubtitle\.php\?id=([0-9]+)/; (1 .. $#字段) { next除非$ _%2; say $ fields [$ _] if $ fields [$ _ + 1] =〜/hebrew.*$var/; } 'unAifctF.html,我累了,但它不工作。我需要逃避它嗎? – buntuser

+0

@buntuser:如果該變量可能包含特殊字符,則應引用它:'/ hebrew。* \ Q $ var \ E /' – choroba

0

問題是*是一個貪婪的運算符,所以它會盡可能地匹配,導致它不會停止在第一個可能的匹配上,而是在最後一次可能的匹配上停止。因此,你應該改變它試圖匹配的內容。問題是你希望它匹配除了另一個「downloadsubtitle.php?id =」之外的任何東西,這在sed中很難。你既可以創建更復雜的sed腳本,或者您可以使用一個簡單的解決方法是假設不會有鏈接和標題之間的任何? S =)

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 

該腳本從將整個文件加載到模式空間(即工作緩衝區)開始。它在前兩行執行此操作。第一行用:「命令」聲明名爲next的標籤。第二行使用N命令將輸入​​的下一行追加到模式空間中,然後跳回到next標籤,但只有在我們還沒有讀取最後一行時纔會執行這兩個命令。第三行刪除所有換行符。

現在,我們用一個換行符(用反斜線後跟一個實際的新行代表)和ID號替換第一個出現downloadsubtitle\.php?id=[0-9][0-9]*

創建了一個新的標籤loop,我們在做之後的第一件事是刪除第一個換行符(因此我們刪除了id之前的所有內容)。

現在我們有一系列命令將提取數字並將其存儲到保留空間(輔助緩衝區)中。我們首先使用h命令將整個圖案空間複製到保持空間中,然後刪除數字後的所有內容,然後將保持和圖案空間的內容與x交換。現在保持空間包含數字,模式空間已恢復爲其值。

爲了防止貪婪搜索,我們會在下一個出現downloadsubtitle\.php?id=[0-9][0-9]*之前放置一個換行符。我們也可以只留下身份證號碼,因爲換行符會指示我們找到了字符串的其餘部分。

現在來搜索部分。總而言之,我們在保持空間中有實際的ID,並且模式空間的第一行是我們想要搜索文本的位置。因此,我們使用搜索表達式從緩衝區起始處搜索字符串hebrewDESPiTE,並且這些字符串不是彼此分開的,也不是從緩衝區的起始位置用換行符分隔的。因此,我們只搜索第一行。

如果找到匹配項,我們使用g從保存空間中獲取ID,p打印它,然後q退出。

如果我們找不到匹配項,我們只需跳回loop標籤,然後搜索下一個發生位置。跳轉之前的條件是爲了防止無限循環。如果沒有什麼可搜索的,它就會退出。

希望這有助於=)