是否可以在字符串中全局修改和替换 $1 (awk) 或 \1 (sed) 值从十进制到十六进制?该字符串可能包含任何十进制值,需要对其进行修改并替换为其等效的十六进制值。
awk 示例:
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 进行子执行和管道操作,但无法将两者结合起来以进行十进制到十六进制的修改和替换。
预期输出:
%2FTest%2DTest%2DTest%2DTest%2DTest%2FTest%2FTest%2F
非常感谢您的帮助。
答案1
使用 GNU 时awk
,R
ecordS
分隔符可以是正则表达式,它匹配的内容存储在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 中进行编码。它还会负责转换%
为%25
、空格%20
、&
到%26
等等。
还有一个问题是如何处理非 ASCII 字符(上面的字符
)?如果它们应该转换为 UTF-8 编码的 URI 编码,例如€
(€, U+20AC, €
) 转换为%E2%82%AC
(该字符的 UTF-8 编码的 3 个字节),那么应该是:
perl -MURI::Escape -MHTML::Entities -lpe '$_ = uri_escape_utf8 decode_entities $_'
使用uri_escape
,您将获得 ISO8859-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 机器上的任何 shell 中使用任何 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
使用 GNU sed,它在 s/// 命令上有 /e 修饰符,我们可以这样做,如下所示:
$ sed -E ":a;s/(.*)&#([0-9]+);(.*)/printf %s '\\1' \"\$(dc -e '37an16o\\2f')\" '\\3'/e;ta" file
- 扩展正则表达式模式下的 GNU sed -E
- GNU dc 将小数转换为十六进制。
- 然后我们通过 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
它本质上做的是:
- 输出为十六进制 (16o)
- 转小数 -> %HEX 等值
- 用换行符分隔十六进制部分
- 将这些非换行符块转换为 dc 字符串,稍后传递给 dc 执行。