解包函数将如何在 perl 中用于此代码 $str =~ s/([^\w ])/'%'.unpack('H2', $1)/eg;

Posted

技术标签:

【中文标题】解包函数将如何在 perl 中用于此代码 $str =~ s/([^\\w ])/\'%\'.unpack(\'H2\', $1)/eg;【英文标题】:how unpack function will work in perl for this code $str =~ s/([^\w ])/'%'.unpack('H2', $1)/eg;解包函数将如何在 perl 中用于此代码 $str =~ s/([^\w ])/'%'.unpack('H2', $1)/eg; 【发布时间】:2020-03-06 08:53:26 【问题描述】:

我在 perl 中有一个代码 $str =~ s/([^\w ])/'%'.unpack('H2', $1)/eg;我不明白 $str 中将存储什么值

【问题讨论】:

【参考方案1】:

假设 $str 使用 UTF-8 编码,并且假设您提供的代码后跟 $str =~ s/ /+/g,则结果是一个可在 URL 中安全使用的 url-encoded 字符串。

具体来说,有问题的代码行用以% 开头的三个字符序列替换除空格之外的所有非单词,后跟表示字符编号的两个十六进制数字。

例如,

foo'sfoo%27s 20%20%25

更好的解决方案是使用来自URI::Escape 的uri_escape(用于使用UTF-8 编码的字符串)或uri_escape_utf8(用于Unicode 代码点的字符串,也就是解码的字符串)。

【讨论】:

abc defabc%20def - 但它明确不转换空格。 @Dave Cross,累了。固定。【参考方案2】:

提供的代码行根据替换规则集 s/([^\w ])/'%'.unpack('H2', $1)/eg 修改 $str 值。

它是如何工作的:

    [^\w] - 查看$str 中的字符不是 \w 被称为 complement 到 \w \w - 表示范围 [A-za-z0-9_],标点符号和 Unicode 标记见 perlre ([^\w]) 捕获找到的字符,将其“存储”在$1 正则表达式修饰符e'%'.unpack('H2',$1) 评估为替换字符串 unpack('H2',$1) - unpack $1 与模板 'H2'(与 $1 关联的字节的十六进制表示) 取 '%' 并将其与解压结果连接 使用第 6 步的结果作为替换字符串 正则表达式修饰符g 指示对$str 中的所有匹配项进行此操作

在此操作之前不知道初始$str 值,无法评估最终结果。

如果初始值已知,则可以访问https://regex101.com/网站评估结果。

没有什么比sample code 展示转型更能说响亮

use feature 'say';

$msg = "Date: Mar 6 2020, Msg: soon Alex's birthday";

$msg =~ s/([^\w ])/'%'.unpack('H2', $1)/eg;

say $msg;

输出

Date%3a Mar 6 2020%2c Msg%3a soon Alex%27s birthday

以下代码演示了“Hello World\n”如何显示为 hex 表示(对于 Dada)。

use feature 'say';

my $msg = "Hello World!\n";

print $msg;

my $a = unpack('H*',$msg);

say $a;

输出

Hello World!
48656c6c6f20576f726c64210a

【讨论】:

@Dada - unpack('H2',$1) 将 $1 的值解压缩为两个 hex 数字(字节的十六进制表示)。请参阅 pack unpack tutorial。 Re "\w - 代表范围[A-za-z0-9_]",甚至没有接近。它匹配 128,919 个不同的字符,而不仅仅是您列出的 63 个。 @ikegami -- 如果我们考虑到 'Unicode' 那么是的,引用 \w [3] 匹配“单词”字符(字母数字加“_”,以及其他连接符标点字符加上 Unicode 标记)。我提供了可以获取此信息的链接。 Re "如果我们考虑到 'Unicode' 那么是的",好吧,如果你使用 \w,你应该提供一串 Unicode 代码点,所以不考虑Unicode是不可能的。 /// 粗体字是正确的,支持我说的。您认为只有 62 个字母数字字符是错误的。 /// Re "我给出了获取此信息的链接。",是的,但是你也提供了错误的信息。 @ikegami -- 我同意你的评论,我没有详细说明,因为 OP 肯定不会理解这种语言。我想他可以得到一个想法,更多信息可以点击链接——我只是想不出简短的描述来传达这些信息。我将扩展这一点的描述。【参考方案3】:

您可以先尝试一下,看看是否能给您提示。

$ perl -E'$str = "&*("; $str =~ s/([^\w ])/"%".unpack('H2', $1)/eg; say $str'
%26%2a%28

所以,我们有一个如下所示的替换运算符:

s/PATTERN/REPLACEMENT/OPTIONS

我们的模式是([^\w ]),这意味着“匹配不是'单词字符'或空格的每个单独字符,并在$1 中捕获该字符。

替换字符串是"%".unpack('H2', $1)。这意味着“字符 '%' 后跟运行 unpack('H2', $1) 的结果。unpack() 用于将字符转换为其 ASCII 码的十六进制等效值。“H”表示“转换为十六进制”和“2”表示产生两个十六进制数字”。

选项是/e,意思是“运行此代码并将输出用作替换字符串”和/g,意思是“对输入字符串中的每个匹配项执行此操作”。

综上所述,您的代码如下:

查找非单词字符 将它们转换为十六进制转义码 在字符串中替换它们

使用URI::Escape 可能是更好的方法。

【讨论】:

以上是关于解包函数将如何在 perl 中用于此代码 $str =~ s/([^\w ])/'%'.unpack('H2', $1)/eg;的主要内容,如果未能解决你的问题,请参考以下文章

perl 将函数解包到 python

如何在 C# 中复制 Perl 的解包功能?

“W”在 Perl 的解包函数中究竟做了啥?

获取 Perl 打包/解包模板的元素数量

Perl 中的解包功能要求

如何从二进制文件中读取块并使用 Python 或 Perl 解包提取结构?