解包函数将如何在 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's
⇒ foo%27s
20%
⇒ 20%25
更好的解决方案是使用来自URI::Escape 的uri_escape
(用于使用UTF-8 编码的字符串)或uri_escape_utf8
(用于Unicode 代码点的字符串,也就是解码的字符串)。
【讨论】:
abc def
⇒ abc%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;的主要内容,如果未能解决你的问题,请参考以下文章