文字列の $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進数の変更と置換のために2つを組み合わせることはできませんでした。

予想出力:

%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

3番目の引数として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)です。
  • 10進数に変換 - >%HEX相当
  • 改行文字で16進数部分を区切ります。
  • これらの改行ではない文字ブロックをDC文字列に変換し、後で実行するためにDCに渡します。

関連情報