Sed

在不依賴 html 實體的情況下進行過濾,基於開始結束匹配的一行巨大字元串,並將文本保持在模式之間,無論長度如何

  • April 15, 2022

我有一個像Pastebin這樣的單行文件,但要長得多。

我的目標是僅過濾

example1 的部分字元串:<a</a>

example2 開頭:以PZend開頭s16

,因此在每種情況下都將文本保持在匹配之間而不依賴於 html 實體

我在一個FreeBSD並且我已經有一個依賴於 html 實體的解決方法

  1. 美化為多行tidy -i -m -w 160 -ashtml -utf8 ~/file
  2. 如果不包含字元串,則刪除行sed -i '' '/\<\/a\>/!d' ~/file

順便說一句,我試圖在不依賴 html 實體的情況下執行直接過濾器。現在我只能得到一個匹配的確切開始,但我不知道我過濾的字元串內容有多長,所以我不能精確到匹配的結束,查看意外結果步驟來重現

重現意外結果的步驟

wget -O ~/file https://pastebin.com/raw/xbti369J
grep -E -o ".{0,0}PZ.{0,46}" ~/file

結果

因為我們要求固定長度,所以我們得到了錯誤的行
PZ</td><td class="s15">€ 1.20</td><td class="s16
PZ</td><td class="s15"></td><td class="s16">A</t
目標是獲得線條結果模式,無論長度如何,如下所示
PZ</td><td class="s15">€ 1.20</td><td class="s16
PZ</td><td class="s15"></td><td class="s16

如果要選擇從 aPZ到最近的每個片段s16,則需要非貪婪匹配,grep(擴展的)正則表達式不支持該匹配,但 GNU為 Perl 樣式表達式grep提供了-Perl 選項:

grep -P -o "PZ.*?s16" ~/file

Perl 表達式 `.*?’ 代表將使整個表達式匹配的任何字元的最短匹配。

這可能仍然不是您要查找的內容,因為PZ匹配項內部還有更多內容,但是據我了解您的範例,您只想要那些PZ後面s16沒有其他匹配項的內容PZ。所以讓我們在第二步中刪除不需要的東西:

grep -P -o "PZ.*?s16" ~/file | sed 's/.*PZ/PZ/'

您想使用 XML 解析器,例如xmllint.

使用下面的 XPath 表達式過濾掉a元素之間的文本:

xmllint --html --xpath '//a/text()' <file>

引用自:https://unix.stackexchange.com/questions/698885