문자열에서 $1(awk) 또는 \1(sed) 값을 10진수에서 16진수로 전역적으로 수정하고 바꾸시겠습니까?

문자열에서 $1(awk) 또는 \1(sed) 값을 10진수에서 16진수로 전역적으로 수정하고 바꾸시겠습니까?

문자열에서 $1(awk) 또는 \1(sed) 값을 10진수에서 16진수로 전역적으로 수정하고 교체할 수 있나요? 문자열에는 10진수 값이 포함될 수 있으며 이를 수정하고 이에 상응하는 16진수 값으로 바꿔야 합니다.

이상한 예:

echo "/Test-Test-Test-Test-Test/Test/Test/" | awk '{gsub("&#([0-9]+);", $1, $0); print}'

sed 예:

echo "/Test-Test-Test-Test-Test/Test/Test/" | sed -E 's/&#([0-9]+);/$(printf "%X" \1)/g;'

echo "/Test-Test-Test-Test-Test/Test/Test/" | sed -E 's/&#([0-9]+);/$(echo "obase=16; \1" | bc)/g;'

printf "%X" 및 bc를 사용하여 하위 실행 및 파이핑을 시도했지만 10진수에서 16진수 수정 및 교체를 위해 두 가지를 결합할 수 없었습니다.

예상 출력:

%2FTest%2DTest%2DTest%2DTest%2DTest%2FTest%2FTest%2F

도움을 주셔서 감사합니다.

답변1

GNU를 사용할 때 awk레코드 R구분 S기호는 정규 표현식일 수 있으며 일치하는 내용은 다음에 저장됩니다 RT.

gawk -v RS='&#[0-9]+;' -v ORS= '1;RT{printf("%%%02X", substr(RT,3))}'

개인적으로 다음을 사용합니다 perl.

perl -pe 's{&#(\d+);}{sprintf "%%%02X", $1}ge'

또한보십시오:

perl -MURI::Escape -MHTML::Entities -lpe '$_ = uri_escape decode_entities $_'

여기에 주어진:

%2FTest-Test-Test-Test-Test%2FTest%2FTest%2F

URI에서 하이픈을 인코딩할 필요가 없기 때문입니다. 또한 , space , to 등 %으로 변환하는 작업도 처리합니다 .%25%20&%26

또 다른 질문은 ASCII가 아닌 문자(위의 문자 )를 처리하는 방법입니다. UTF-8로 인코딩된 URI 인코딩으로 변환해야 하는 경우(예: €(€, U+20AC, ) 는 (UTF-8로 인코딩된 문자의 3바이트) €로 변환 됩니다.%E2%82%AC

perl  -MURI::Escape -MHTML::Entities -lpe '$_ = uri_escape_utf8 decode_entities $_'

를 사용하면 uri_escapeISO8859-1(latin1이라고도 함) 인코딩을 얻을 수 있는데, 오늘날에는 원하는 대로 인코딩되지 않을 것입니다(최대 문자로 제한됩니다 ÿ). 다른 솔루션은 예를 들어 절대적 €으로 %20AC잘못된 것으로 해석됩니다 .

답변2

세 번째 인수로 GNU awk를 사용하십시오 match().

$ echo "/Test-Test-Test-Test-Test/Test/Test/" |
awk '{
    while ( match($0,/(.*)&#([0-9]+);(.*)/,a) ) {
        $0 = a[1] sprintf("%%%02X",a[2]) a[3]
    }
    print
}'
%2FTest%2DTest%2DTest%2DTest%2DTest%2FTest%2FTest%2F

그렇지 않으면 모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.

$ echo "/Test-Test-Test-Test-Test/Test/Test/" |
awk '{
    while ( match($0,/&#[0-9]+;/) ) {
        $0 = substr($0,1,RSTART-1) sprintf("%%%02X",substr($0,RSTART+2,RLENGTH-3)) substr($0,RSTART+RLENGTH)
    }
    print
}'
%2FTest%2DTest%2DTest%2DTest%2DTest%2FTest%2FTest%2F

답변3

s/// 명령에 /e 수정자가 있는 GNU sed를 사용하면 다음과 같이 이 작업을 수행할 수 있습니다.

$ sed -E ":a;s/(.*)&#([0-9]+);(.*)/printf %s '\\1' \"\$(dc -e '37an16o\\2f')\" '\\3'/e;ta" file
  • 확장 정규식 모드의 GNU sed -E
  • GNU dc는 10진수를 16진수로 변환합니다.
  • 그런 다음 t 명령을 통해 교체를 반복합니다.

GNU sed가 아직 s/// 명령의 /e 수정자를 지원하지 않는 경우 입력 행을 GNU dc 코드 블록으로 변환하고 이를 dc로 파이프할 수 있습니다.

< file \
sed -E '1i\
16o
  s/&#([0-9]+);/\n37an\1n\n/g
  s/([^\n]*)/[&]/g
  s/([^\n]*\n){2}/&x/g
  s/\nx/x /g;y/\n/n/
  s/$/pc/;s/.*/[&]x/
' | dc

본질적으로 수행하는 작업은 다음과 같습니다.

  • 출력은 16진수(16o)입니다.
  • 십진수로 변환 -> %HEX 상당
  • 개행 문자로 16진수 부분을 구분합니다.
  • 이러한 개행이 아닌 문자 블록을 DC 문자열로 변환하고 나중에 실행을 위해 DC에 전달합니다.

관련 정보