English | 简体中文
选择的 3 个字母:i
、e
、x
。
$i=$?+$?
$e=$i+$i
$xi=$x=$e+$i
$xe=""+$x+$x
$xx=""+$x+--$e
$x=(""+$?)[$i]
iex "`$ex=""``$x{$xe}"";`$xe=""``$x{$xx}"""
$ii=$e+++$i
$ix=$ii+$i
$ei=$e*$i
$x="``$x{"
iex "`$e=""$x$e$ei}e$x$xi$xe}$x$xi$xe}$x$xi$ex}, $x$ii$ix}$x$xi$ex}$x$ix$i}$x$xi$xe}$x$xi$e}!"""
$e
压成一行时语句结尾需要有分号。
$i=$?+$?;$e=$i+$i;$xi=$x=$e+$i;$xe=""+$x+$x;$xx=""+$x+--$e;$x=(""+$?)[$i];iex "`$ex=""``$x{$xe}"";`$xe=""``$x{$xx}""";$ii=$e+++$i;$ix=$ii+$i;$ei=$e*$i;$x="``$x{";iex "`$e=""$x$e$ei}e$x$xi$xe}$x$xi$xe}$x$xi$ex}, $x$ii$ix}$x$xi$ex}$x$ix$i}$x$xi$xe}$x$xi$e}!""";$e
因为不能直接出现数字了,所以需要想办法得到第一个 Int 类型的值。发现数组下标为空字符串 ''
时可以得到数组的第一个元素,但是如果想要后面的字母的话,PowerShell 并没有提供 pop 等函数。[3]数字字面量也都至少需要有 0
出现。所以只能通过其他类型隐式转换出 Int 来。
$i = $? + $?
剩下的大部分操作都是在构造其他数字,代码的长度应该可以再压缩一点。
$x = ("" + $?)[$i]
-
+
运算符的两个参数类型不一致的时候,会将第二个参数隐式转换为第一个参数的类型。故此处$e
为 String"True"
。
至此,我们有了所需的数字和字母 u
,可以用 "`u{x}"
来生成一切字符了。不过,"Hello World!"
除了可以直接输入的 e
、空格和 !
,十六进制值中还需要 c
和 f
。幸好这两个的编码分别为 63
和 66
,没有 a-f 出现。$e
实际上就是:
$e = "``u{48}e``u{6c}``u{6c}``u{6f}, ``u{57}``u{6f}``u{72}``u{6c}``u{64}!";
iex "`$ex=""``$x{$xe}"";`$xe=""``$x{$xx}"""
-
字符串用双引号的好处是可以直接嵌入变量。如果要 escape 的话,需要在
$
、“、
前面加上
;”
也可以自身重复两次""
来 escape。[6]
-
变量赋值时可以直接是命令的输出。比如旧版 PowerShell 可以通过
$ls = ls; $ls[x][x]
拿到 ls 命令表头具体的一个 Char,或许有的命令的输出包含全部所需的字母。但是新版中大部分命令的输出不再是字符串而是对象了,两次下标拿到的仍然和原结果一样。 -
$error
是一个存放了错误信息字符串的数组。[7]不过,错误会直接输出,不符合「该程序运行后输出 Hello, World!, 有且仅有该内容,要求分毫不差」的要求。