큰 줄 문자열의 시작-끝 일치를 기반으로 html 엔터티에 의존하지 않고 필터링하고 길이에 관계없이 패턴 사이에 텍스트를 유지합니다.

큰 줄 문자열의 시작-끝 일치를 기반으로 html 엔터티에 의존하지 않고 필터링하고 길이에 관계없이 패턴 사이에 텍스트를 유지합니다.

다음과 같은 한 줄 파일이 있습니다.파스퇴르 빈그러나 훨씬 더 길다.


내 목표는 example1: start with <aend with </a>
example2: start with PZend with 의 문자열 부분 만 필터링하는 것입니다 s16
. 따라서 각 경우 텍스트는 HTML 엔터티에 의존하지 않고 일치 항목 사이에 유지됩니다.

FreeBSDHTML 엔터티에 의존하는 해결 방법이 이미 있습니다.

  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

답변1

와 같은 XML 파서를 사용하고 싶습니다 xmllint.

a다음 XPath 표현식을 사용하여 요소 사이의 텍스트를 필터링합니다 .

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

답변2

PZa 에서 가장 가까운 것까지 모든 조각을 선택하려면 s16탐욕스럽지 않은 일치가 필요합니다. 이는 (확장) 정규 표현식에서 지원되지 않지만 grepGNU에는 grepPerl 스타일 표현식에 대한 erl 옵션이 있습니다.-P

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

Perl 표현식 ".*?"는 전체 표현식을 일치시키는 문자 중 가장 짧은 일치를 나타냅니다.

PZ경기 내부에 더 많은 것이 있기 때문에 이것은 여전히 ​​당신이 원하는 것이 아닐 수도 있지만 , 당신의 예를 이해하면 PZ뒤에 있는 것만 필요하고 s16그 사이에는 아무것도 필요하지 않습니다. PZ이제 두 번째 단계에서 불필요한 항목을 제거해 보겠습니다.

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

답변3

이를 수행하는 방법에는 여러 가지가 있습니다.

1PCRE가 활성화된 GNU grep. 여기서는 탐욕스럽지 않은 정규식 *?를 부정적인 예측과 함께 활용하여 PZ와 s16 사이에 발생하는 모든 PZ를 삭제합니다.

grep -Po 'PZ(?:(?!PZ).)*?s16' file

2 그러한 grep 버전에 액세스할 수 없는 경우 정규식을 지원하는 원래 버전인 Perl을 사용할 수 있습니다.

perl -lne 'print for /PZ(?:(?!PZ).)*?s16/g' file

이를 위해 sed를 사용할 수 있습니다. 첫 번째 단계에서는 PZ 및 s16을 BOL 및 EOL로 표시합니다. 이 수정된 입력은 PZ로 시작하고 s16으로 끝나는 줄을 선택하는 두 번째 sed로 전달되며 내부적으로 PZ를 포함해서는 안 됩니다.

< file \
sed 's/PZ/\n&/g;s/s16/&\n/g' |
sed '/^PZ.*s16$/!d;/..*PZ/d' |
cat

4 우리를. 여기서는 단 하나의 sed 호출만 사용됩니다. GNU sed가 필요합니다.

sed '/\n/{
  /^PZ[^\n]*s16/!D
  s//&\n/;P;D;}
  s/PZ/\n&/g;D
' file

관련 정보