如何将字符串转换为修改后的十六进制表示?
Posted
技术标签:
【中文标题】如何将字符串转换为修改后的十六进制表示?【英文标题】:How to turn a string into a modified hex representation? 【发布时间】:2021-09-30 21:30:24 【问题描述】:我想把一个字符串变成这样的
AaAa
进入
这样的字符串
%<41>%<61>%<41>%<61>
对于我熟悉的编程语言来说足够简单,但是对于 bash,我无法获得正确的管道来做我想做的事情:
将字符串拆分为字符数组 将每个字符转换为十六进制 将每个十六进制值包装成%<FF>
连接字符串
这是我目前的方式,让我走到了一半:
echo -n "AaAa" | od -A n -t x1
【问题讨论】:
【参考方案1】:如果您已经在使用od
,
printf "%%<%s>" $(od -A n -t x1<<<"AaAa")
对于没有od
的全bash,
while read -r -N 1 c; do printf "%%<%02X>" "$( printf "%d" \'$c )"; done <<< AaAa
这种方法的缺点是它为每个字符生成一个子shell,并假定为 ASCII/UTF8。
编辑
@Shawn 指出你不需要 subshell -
while read -r -N 1 c; do printf "%%<%02X>" \'$c; done <<< AaAa
不过,我注意到这些会在您的输出中留下字符串终止符,并意识到我可以通过将数据分配给变量并使用内置解析工具来消除它和 read
。
$: x=AaAa && for((i=0;i<$#x;i++)); do printf "%%<%02X>" \'$x:i:1; done; echo
%<41>%<61>%<41>%<61>
【讨论】:
正如所写,这不会在 POSIX shell (/bin/sh
) 上运行。它还具有输入大小的上限。这些可能是也可能不是问题。
如果你想要只是 bash,c.f. ***.com/questions/67870452/…
bash
被明确提及。
在纯 bash 版本中不需要第二个 printf
...printf "%%<%02X>" "'$c"
有效。
第一个变体应该适用于更大的输入:od -A n -t x1 <<<"AaAa" | xargs printf "%%<%s>"
【参考方案2】:
一个简单的 Perl 替换就可以解决问题:
echo -n AaAa | perl -pe's/(.)/ sprintf "%%<%02X>", ord($1) /seg'
更短:
echo -n AaAa | perl -ne'printf "%%<%02X>", $_ for unpack "C*"'
在这两种情况下,输出都是预期的
%<41>%<61>%<41>%<61>
(没有添加尾随换行符。如果需要,请附加; END print "\n"
。)
【讨论】:
【参考方案3】:您可以通过管道传递到sed
以将每个字节包装在%<>
中,然后删除空格。
echo -n "AaAa" | od -A n -t x1 | sed -E -e 's/[a-z0-9]+/%<&>/g' -e 's/ //g'
【讨论】:
【参考方案4】:你可以使用perl:
echo -n AaAa | perl -ne 'for $c (split//) printf("%%<%02X>", ord($c)); '
输出
%<41>%<61>%<41>%<61>
【讨论】:
这个结果也可以通过管道处理吗?既然你先回复了,我会把你的标记为答案,但现在我在 WSL 中出现了奇怪的行为 @Dbl 是的,它应该可以通过管道正常工作。我在编写 oneliner 时实际上使用了 WSL。结果有什么奇怪的地方? 格式已关闭,但可能是 wsl 问题 @Dbl 嗯,它看起来符合我的预期。格式如何关闭? WSL 不是操作系统。我使用 Ubuntu(通过 WSL),它运行良好。该命令没有特定于操作系统的内容(尽管您必须调整 Windowscmd
shell 的引用)。【参考方案5】:
也许awk
echo -n "AaAa" |
od -A n -t x1 |
awk 'BEGIN ORS = "" for (i = 1; i <= NF; i+=1) print "%<"$i">"'
【讨论】:
以上是关于如何将字符串转换为修改后的十六进制表示?的主要内容,如果未能解决你的问题,请参考以下文章