Q 语言§
字符串通常在 Raku 代码中使用某种形式的引用结构来表示。其中最简化的形式是 Q
,可以通过快捷方式 「…」
使用,或者通过 Q
后跟任何一对包围文本的定界符来使用,包括许多 Unicode 对。但是,大多数情况下,您只需要 '…'
或 "…"
,将在以下部分中详细介绍。
有关在正则表达式中应用引用的信息,请参阅 正则表达式文档。
字面字符串:Q§
Q[A literal string]「More plainly.」Q^Almost any non-word character can be a delimiter!^Q「「Delimiters can be repeated/nested if they are adjacent.」」Q⦅Quoting with fancy unicode pairs⦆
定界符可以嵌套,但在普通的 Q
形式中,不允许反斜杠转义。换句话说,基本的 Q
字符串尽可能地字面化。
某些定界符不允许紧跟在 Q
、q
或 qq
之后。任何在 标识符 中允许的字符都不允许使用,因为在这种情况下,引用结构连同这些字符一起被解释为标识符。此外,( )
不允许,因为这被解释为函数调用。如果您仍然希望使用这些字符作为定界符,请用空格将它们与 Q
、q
或 qq
分隔开。请注意,某些自然语言在字符串的右侧使用左定界引号。Q
不支持这些,因为它依赖于 unicode 属性来区分左右定界符。
Q'this will not work!'Q(this won't work either!)
上面的示例将产生错误。但是,这将起作用
Q (this is fine, because of space after Q)Q 'and so is this'Q<Make sure you <match> opening and closing delimiters>Q{This is still a closing curly brace → \}
这些示例产生
this is fine, because of space after Qand so is thisMake sure you <match> opening and closing delimitersThis is still a closing curly brace → \
引用结构的行为可以通过副词来修改,如后面的部分中详细解释。
短 | 长 | 含义 |
:x | :exec | 作为命令执行并返回结果 |
:w | :words | 按单词拆分结果(无引号保护) |
:ww | :quotewords | 按单词拆分结果(有引号保护) |
:q | :single | 插值 \\、\qq[...] 和使用 \ 转义定界符 |
:double | 使用 :s、:a、:h、:f、:c、:b 插值 | |
:s | :scalar | 插值 $ 变量 |
:a | :array | 插值 @ 变量(在后缀之后) |
:h | :hash | 插值 % 变量(在后缀之后) |
:f | :function | 插值 & 调用 |
:c | :closure | 插值 {...} 表达式 |
:b | :backslash | 启用反斜杠转义(\n、\qq、\$foo 等) |
:to | :heredoc | 将结果解析为 heredoc 终止符 |
:v | :val | 如果可能,转换为同形异义词 |
这些副词可以与 Q
一起使用,因此即使引用运算符不插值,它也会插值
my = :is-mighty;say Q "Þor %þ<>"; # OUTPUT: «Þor %þ<>»say Q:h"Þor %þ<>"; # OUTPUT: «Þor is-mighty True»= :42foo, :33bar;say Q:h:c "Þor %þ<> → { [+] %þ.values}"; # OUTPUT: «Þor bar 33foo 42 → 75»my = <33 44>; say Q:a "Array contains @þ[]"; # OUTPUT: «Array contains 33 44»say Q:v<33> + 3; # OUTPUT: «36»
默认情况下,如所示,Q
直接引用,不会对引用的字符串进行任何形式的转换。副词将修改其行为,例如,将字符串转换为同形异义词(使用 :v
副词),或允许插值哈希(通过 :h
)或 {}
代码段(通过 :c
)。数组和哈希必须后跟后缀;也就是说,带符号的标识符不会插值,但后跟索引、decont 运算符或带括号的方法调用,它将
my = <33 44>;say Q:a "Array contains @þ.elems()"; # OUTPUT: «Array contains 2»
在没有括号的情况下,相同的代码在没有后缀运算符的情况下,将不会插值。
转义:q§
'Very plain';q[This back\slash stays];q[This back\\slash stays]; # Identical outputq{This is not a closing curly brace → \}, but this is → };Q :q $There are no backslashes here, only lots of \$\$\$!$;'(Just kidding. There\'s no money in that string)';'No $interpolation {here}!';Q:q!Just a literal "\n" here!;
q
形式允许使用反斜杠转义否则会结束字符串的字符。反斜杠本身也可以转义,如上面的第三个示例所示。通常的形式是 '…'
或 q
后跟一个定界符,但它也可以作为 Q
上的副词使用,如上面的第五个和最后一个示例所示。
这些示例产生
Very plain This back\slash stays This back\slash stays This is not a closing curly brace → } but this is → There are no backslashes here, only lots of $$$! (Just kidding. There's no money in that string) No $interpolation {here}! Just a literal "\n" here
\qq[...]
转义序列启用 qq
插值 用于字符串的一部分。当您的字符串中包含 HTML 标记时,使用此转义序列非常方便,以避免将尖括号解释为哈希键
my = 'foo';say '<code>$var</code> is <var>\qq[$var.uc()]</var>';# OUTPUT: «<code>$var</code> is <var>FOO</var>»
插值:qq§
my = 'blue';say "My favorite color is $color!"; # OUTPUT: «My favorite color is blue!»
qq
形式 - 通常使用双引号编写 - 允许插值反斜杠转义序列(如 q:backslash
)、所有带符号变量(如 q:scalar:array:hash:function
)以及 {...}
内的任何代码(如 q:closure
)。
插值变量§
在 qq
引用的字符串中,您可以使用带符号的变量来触发变量值的插值。带有 $
符号的变量会在它们出现时进行插值(除非转义);这就是为什么在上面的示例中,"$color"
变成了 blue
。
但是,带有其他符号的变量只有在您在变量后面加上相应的后缀([]
用于数组,<>
用于哈希,&
用于子程序)时才会触发插值。这允许您编写像 "[email protected]"
这样的表达式,而不会插值 @raku
变量。
要插值一个数组(或其他 Positional
变量),请在变量名后面附加一个 []
my = "Felix", "Danielle", "Lucinda";say "@neighbors[] and I try our best to coexist peacefully."# OUTPUT: «Felix Danielle Lucinda and I try our best to coexist peacefully.»
或者,除了使用 []
之外,您还可以通过在方法名后面加上括号来调用方法,从而插值数组。因此,以下代码将起作用
say "@neighbors.join(', ') and I try our best to coexist peacefully."# OUTPUT: «Felix, Danielle, Lucinda and I try our best to coexist peacefully.»
但是,"@example.com"
会生成 @example.com
。
say "uc 'word'"; # OUTPUT: «uc 'word'»say "&uc 'word'"; # OUTPUT: «&uc 'word'»say "&uc('word')"; # OUTPUT: «WORD»# OUTPUT: «abcDEFghi»
要插值一个哈希(或其他 Associative
变量),请使用 <>
后缀运算符。
my = :1st; say "abc%h<st>ghi";# OUTPUT: «abc1ghi»
qq
插值变量的方式与 q:scalar:array:hash:function
相同。您可以使用这些副词(或它们的简写形式 q:s:a:h:f
)来插值变量,而不会启用其他 qq
插值。
插值闭包§
qq
的另一个特性是能够使用花括号从字符串中插值 Raku 代码
my (, , ) = 4, 3.5, 3;say "This room is m by m by m."; # OUTPUT: «This room is 4m by 3.5m by 3m.»say "Therefore its volume should be m³!"; # OUTPUT: «Therefore its volume should be 42m³!»
这提供了与 q:closure
/q:c
引号形式相同的功能。
插值转义代码§
qq
引号形式还插值反斜杠转义序列。其中一些打印不可见/空白 ASCII 控制代码或空白字符
序列 | 十六进制值 | 字符 | 参考 URL |
\0 | \x0000 | Nul | https://util.unicode.org/UnicodeJsps/character.jsp?a=0000 |
\a | \x0007 | Bel | https://util.unicode.org/UnicodeJsps/character.jsp?a=0007 |
\b | \x0008 | 退格 | https://util.unicode.org/UnicodeJsps/character.jsp?a=0008 |
\e | \x001B | Esc | https://util.unicode.org/UnicodeJsps/character.jsp?a=001B |
\f | \x000C | 换页 | https://util.unicode.org/UnicodeJsps/character.jsp?a=000C |
\n | \x000A | 换行 | https://util.unicode.org/UnicodeJsps/character.jsp?a=000A |
\r | \x000D | 回车 | https://util.unicode.org/UnicodeJsps/character.jsp?a=000D |
\t | \x0009 | 制表符 | https://util.unicode.org/UnicodeJsps/character.jsp?a=0009 |
qq
还支持两个多字符转义序列:\x
和 \c
。您可以使用 \x
或 \x[]
以及 Unicode 字符的十六进制代码或字符列表
my = "I \x2665 Raku!";say ;# OUTPUT: «I ♥ Raku!»= "I really \x[2661,2665,2764,1f495] Raku!";say ;# OUTPUT: «I really ♡♥❤💕 Raku!»
您还可以使用 \c
和该字符的 unicode 名称、命名序列 或 名称别名 来创建 Unicode 字符
my = "Camelia \c[BROKEN HEART] my \c[HEAVY BLACK HEART]!";say ;# OUTPUT: «Camelia 💔 my ❤!»
有关更多详细信息,请参阅 Unicode 文档页面上对 \c[] 的描述。
qq
提供与 q:backslash
/q:b
提供的相同的转义序列插值。
阻止插值和处理缺失值§
您可以通过转义符号或其他初始字符来阻止 qq
引用的字符串中的任何不必要的插值
say "The \$color variable contains the value '$color'"; # OUTPUT: «The $color variable contains the value 'blue'»
对未定义值的插值将引发一个控制异常,该异常可以在当前块中使用 CONTROL 捕获。
sub niler ;my Str = niler;say("$a.html", "sometext");say "alive"; # this line is dead codeCONTROL ;
单词引用:qw §
qw|! @ # $ % ^ & * \| < > | eqv '! @ # $ % ^ & * | < >'.words.list;q:w { [ ] \{ \} } eqv ('[', ']', '{', '}');Q:w | [ ] { } | eqv ('[', ']', '{', '}');
:w
形式,通常写成 qw
,将字符串拆分为“单词”。在此上下文中,单词被定义为由非空白字符组成的序列,这些序列由空白字符隔开。q:w
和 qw
形式继承了 q
和单引号字符串分隔符的插值和转义语义,而 Qw
和 Q:w
继承了 Q
引号的非转义语义。
此形式优先于使用多个引号和逗号来表示字符串列表。例如,您可以这样写
my = 'left', 'right,', 'up', 'down';
写和读这个更容易
my = qw|left right up down|;
单词引用: < >
§
say <a b c> eqv ('a', 'b', 'c'); # OUTPUT: «True»say <a b 42> eqv ('a', 'b', '42'); # OUTPUT: «False», the 42 became an IntStr allomorphsay < 42 > ~~ Int; # OUTPUT: «True»say < 42 > ~~ Str; # OUTPUT: «True»
尖括号引用类似于 qw
,但它具有额外的功能,可以让你构建 异形词 或某些数字的字面量
say <42 4/2 1e6 1+1i abc>.raku;# OUTPUT: «(IntStr.new(42, "42"), RatStr.new(2.0, "4/2"), NumStr.new(1000000e0, "1e6"), ComplexStr.new(<1+1i>, "1+1i"), "abc")»
要构建 Rat
或 Complex
字面量,请在数字周围使用尖括号,不要添加任何额外的空格
say <42/10>.^name; # OUTPUT: «Rat»say <1+42i>.^name; # OUTPUT: «Complex»say < 42/10 >.^name; # OUTPUT: «RatStr»say < 1+42i >.^name; # OUTPUT: «ComplexStr»
与 42/10
和 1+42i
相比,没有涉及除法(或加法)运算。这对于例程签名中的字面量很有用,例如
sub close-enough-π (<355/113>)close-enough-π 710/226; # OUTPUT: «Your π is close enough!»
# WRONG: can't do this, since it's a division operationsub compilation-failure (355/113)
带引号保护的单词引用: qww§
qw
形式的单词引用将按字面意义处理引号字符,并将它们保留在生成的单词中
say qw{"a b" c}.raku; # OUTPUT: «("\"a", "b\"", "c")»
使用 qww
变体,你可以使用引号字符将字符串嵌入到单词引用结构中
say qww{"a b" c}.raku; # OUTPUT: «("a b", "c")»
其他类型的引号也支持,它们具有通常的语义
my = 'here';my = 'there';say qww{ ’this and that’ “$one or $other” 「infinity and beyond」 }.raku;# OUTPUT: «("this and that", "here or there", "infinity and beyond")»
嵌入字符串的分隔符始终被视为单词分隔符
say qww{'alpha'beta'gamma' 'delta'"epsilon"}.raku; # OUTPUT: «("alpha", "beta", "gamma", "delta", "epsilon")»
带插值的单词引用: qqw§
qw
形式的单词引用不会插值变量
my = 42; say qw{$a b c}; # OUTPUT: «$a b c»
因此,如果你希望在引用的字符串中插值变量,你需要使用 qqw
变体
my = 42;my = qqw{$a b c};say ; # OUTPUT: «[42 b c]»
请注意,变量插值发生在单词拆分之前
my = "a b";my = qqw{$a c};.say for ; # OUTPUT: «abc»
带插值和引号保护的单词引用: qqww§
qqw
形式的单词引用将按字面意义处理引号字符,并将它们保留在生成的单词中
my = 42; say qqw{"$a b" c}.raku; # OUTPUT: «("\"42", "b\"", "c")»
使用 qqww
变体,你可以使用引号字符将字符串嵌入到单词引用结构中
my = 42; say qqww{"$a b" c}.raku; # OUTPUT: «("42 b", "c")»
嵌入字符串的分隔符始终被视为单词分隔符
say qqww{'alpha'beta'gamma' 'delta'"epsilon"}.raku; # OUTPUT: «("alpha", "beta", "gamma", "delta", "epsilon")»
与 qqw
形式不同,插值也总是拆分(除了在嵌入字符串中发生的插值)
my = "now";= 'ni';my = qqww<$time$time "$_$_">;.say for ; # OUTPUT: «nownow4242nini»
引号保护发生在插值之前,插值发生在单词拆分之前,因此来自插值变量内部的引号只是字面引号字符
my = "1 2";say qqww{"$a" $a}.raku; # OUTPUT: «("1 2", "1", "2")»my = "1 \"2 3\"";say qqww{"$b" $b}.raku; # OUTPUT: «("1 \"2 3\"", "1", "\"2", "3\"")»
带插值和引号保护的单词引用: « »§
这种引用风格类似于 qqww
,但它还具有构建 异形词 的额外好处(使其在功能上等同于 qq:ww:v)。« »
的 ASCII 等效项是双尖括号 << >>
。
# Allomorph Constructionmy = 42; say « b c ».raku; # OUTPUT: «(IntStr.new(42, "42"), "b", "c")»my = 42; say << $a b c >>.raku; # OUTPUT: «(IntStr.new(42, "42"), "b", "c")»# Quote Protectionmy = 42; say « "$a b" c ».raku; # OUTPUT: «("42 b", "c")»my = 42; say << "$a b" c >>.raku; # OUTPUT: «("42 b", "c")»
Shell 引用: qx§
要将字符串作为外部程序运行,不仅可以将字符串传递给 shell
或 run
函数,还可以执行 shell 引用。但是,有一些细微之处需要考虑。qx
引号不会插值变量。因此
my = "there";say
只打印 hello
。但是,如果你在调用 raku
之前声明了一个环境变量,它将在 qx
中可用,例如
WORLD="there" raku> say
现在将打印 hello there
。
调用 qx
的结果将被返回,因此此信息可以分配给一个变量以供以后使用
my = ;say ; # OUTPUT: «hello!»
另请参阅 shell、run 和 Proc::Async
,了解执行外部命令的其他方法。
带插值的 Shell 引用: qqx§
如果希望在外部命令中使用 Raku 变量的内容,则应使用 qqx
shell 引用结构
my = "there";say ; # OUTPUT: «hello there»
再次,外部命令的输出可以保存在一个变量中。
my = "cool";my = "-i";my = "/usr/share/dict/words";my = ;# runs the command: grep -i cool /usr/share/dict/wordssay ; # OUTPUT: «CooleyCooley'sCoolidgeCoolidge'scool...»
注意在外部命令中使用的 Raku 变量的内容;恶意内容可用于执行任意代码。参见 qqx
陷阱
另请参见 run 和 Proc::Async
,了解执行外部命令的更好方法。
Heredocs: :to§
使用heredoc编写多行字符串文字的一种便捷方法,它允许您自己选择分隔符。
say
heredoc的内容始终从下一行开始,因此您可以(也应该)完成该行。
my = my-escaping-function(
如果终止符缩进,则从字符串文字中删除该缩进量。因此,此heredoc
say
产生此输出
Here is some multi line string
Heredocs 包括终止符之前的换行符。
要允许变量插值,请使用qq
形式,但您随后必须转义元字符\{
以及$
(如果它不是定义变量的符号)。例如
my = 'db.7.3.8';my = qq:to/END/option \;ENDsay ;
将产生
option { file "db.7.3.8"; };
其他一些需要注意的情况是看起来无害的情况,其中文本看起来像 Raku 表达式。例如,以下内容会生成错误
my $title = 'USAFA Class of 1965'; say qq:to/HERE/; <a href='https://usafa-1965.org'>$title</a> HERE # Output: Type Str does not support associative indexing. in block <unit> at here.raku line 2
$title
右边的尖括号使它看起来像 Raku 的哈希索引,而实际上它是一个 Str
变量,因此出现了错误消息。一种解决方案是用花括号括起标量,这是在任何插值引号结构中输入表达式的其中一种方法。
say qq:to/HERE/; <a href='https://usafa-1965.org'>{$title}</a> HERE
另一种选择是转义<
字符以避免将其解析为索引运算符的开头。
say qq:to/HERE/; <a href='https://usafa-1965.org'>$title\</a> HERE
由于heredoc 可能非常长,但仍被 Raku 解释为单行,因此有时很难找到错误的来源。调试错误的一种粗略方法是从代码中第一个可见行开始,将其视为仅包含该行的heredoc。然后,直到出现错误,依次添加每一行。(创建 Raku 程序来执行此操作留给读者作为练习。)
您可以在同一行中开始多个 Heredocs。如果您这样做,第二个 heredoc 将在第一个 heredoc 结束之后才开始。
my (, ) = qq:to/END1/say $first; # OUTPUT: «FIRSTMULTILINESTRING»say $second; # OUTPUT: «SECONDMULTILINESTRING»
Unquoting§
文字字符串允许通过使用以下转义序列来插值嵌入的引号结构
my ="quaggas";say 'These animals look like \qq[$animal]'; # OUTPUT: «These animals look like quaggas»say 'These animals are \qqw[$animal or zebras]'; # OUTPUT: «These animals are quaggas or zebras»
在此示例中,\qq
将执行双引号插值,而\qqw
将执行带插值的词语引号。如上所述转义任何其他引号结构将以相同的方式起作用,允许在文字字符串中进行插值。