AnyMath 文档

弦乐器

字符串是有限的字符序列。 当然,真正的麻烦来了,当一个人问一个字符是什么。 说英语的人所熟悉的字符是字母 A, B, C 等。,连同数字和常用标点符号。 这些字符与0到127之间的整数值的映射一起被标准化https://en.wikipedia.org/wiki/ASCII[ASCII]标准。 当然,还有许多其他用于非英语语言的字符,包括带有口音和其他修改的ASCII字符的变体,相关的脚本,如西里尔文和希腊文,以及与ASCII和英语完全无关的脚本,包括阿拉伯语、汉语、希伯来语、印地语、日语和韩语。 该https://en.wikipedia.org/wiki/Unicode[Unicode]标准解决了字符到底是什么的复杂性,并被普遍接受为解决这个问题的最终标准。 根据您的需要,您可以完全忽略这些复杂性,只是假装只存在ASCII字符,或者您可以编写代码来处理处理非ASCII文本时可能遇到的任何字符或编码。 Julia使处理纯ASCII文本变得简单而高效,处理Unicode尽可能简单而高效。 特别是,您可以编写C风格的字符串代码来处理ASCII字符串,它们将按预期工作,无论是在性能还是语义方面。 如果此类代码遇到非ASCII文本,它将优雅地失败,并显示明确的错误消息,而不是默默地引入损坏的结果。 发生这种情况时,修改代码以处理非ASCII数据非常简单。

关于Julia的字符串,有一些值得注意的高级功能:

*Julia中用于字符串(和字符串文字)的内置具体类型为 字符串. 这支持全系列的https://en.wikipedia.org/wiki/Unicode[Unicode]字符通过https://en.wikipedia.org/wiki/UTF-8[UTF-8]编码。 (一 转码/转码函数提供转换为/从其他Unicode编码。) *所有字符串类型都是抽象类型的子类型 抽象字符串,和外部包定义附加 抽象字符串 子类型(例如用于其他编码)。 如果定义一个需要字符串参数的函数,则应将类型声明为 抽象字符串 以便接受任何字符串类型。 *与C和Java一样,但与大多数动态语言不同,Julia具有用于表示单个字符的一流类型,称为 摘要:. 内置的 查尔的亚型 摘要: 是一种32位基元类型,可以表示任何Unicode字符(并且基于UTF-8编码)。 *和Java一样,字符串是不可变的: 抽象字符串 对象不能更改。 若要构造不同的字符串值,请从其他字符串的部分构造一个新字符串。 *从概念上讲,字符串是从索引到字符的_partial function_:对于某些索引值,不返回任何字符值,而是抛出异常。 这允许通过编码表示的字节索引而不是字符索引来有效地索引字符串,这对于Unicode字符串的可变宽度编码来说是不能有效和简单地实现的。

人物

A 查尔 值表示单个字符:它只是一个32位原始类型,具有特殊的字面表示和适当的算术行为,并且可以转换为表示https://en.wikipedia.org/wiki/Code_point[Unicode码位]。 (Julia包可以定义 摘要:,例如优化其他操作https://en.wikipedia.org/wiki/Character_encoding[文本编码]。 下面是如何做到的 查尔 值是输入和显示的(请注意,字符文字是用单引号分隔的,而不是双引号):

julia> c = 'x'
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)

julia> typeof(c)
Char

您可以轻松地转换 查尔 到其整数值,即代码点:

julia> c = Int('x')
120

julia> typeof(c)
Int64

在32位架构上, 类型(c)Int32. 您可以将整数值转换回 查尔 同样容易:

julia> Char(120)
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)

并非所有整数值都是有效的Unicode代码点,但为了性能, 查尔 转换不会检查每个字符值是否有效。 如果要检查每个转换的值是否是有效的代码点,请使用 [医价值]功能:

julia> Char(0x110000)
'\U110000': Unicode U+110000 (category In: Invalid, too high)

julia> isvalid(Char, 0x110000)
false

在撰写本文时,有效的Unicode代码点是 U+0000 通过 U+D7FFU+E000 通过 U+10FFFF. 这些还没有全部被赋予可理解的含义,也不一定可以被应用程序解释,但所有这些值都被认为是有效的Unicode字符。

您可以使用以下方法在单引号中输入任何Unicode字符 \u 后跟最多四个十六进制数字或 \U 后跟最多八个十六进制数字(最长有效值只需要六个):

julia> '\u0'
'\0': ASCII/Unicode U+0000 (category Cc: Other, control)

julia> '\u78'
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)

julia> '\u2200'
'∀': Unicode U+2200 (category Sm: Symbol, math)

julia> '\U10ffff'
'\U10ffff': Unicode U+10FFFF (category Cn: Other, not assigned)

Julia使用系统的区域设置和语言设置来确定哪些字符可以按原样打印,哪些字符必须使用泛型转义输出 \u\U 输入表单。 除了这些Unicode转义形式之外,所有https://en.wikipedia.org/wiki/C_syntax#Backslash_escapes[C的传统转义输入形式]也可以使用:

julia> Int('\0')
0

julia> Int('\t')
9

julia> Int('\n')
10

julia> Int('\e')
27

julia> Int('\x7f')
127

julia> Int('\177')
127

你可以做比较和有限数量的算术与 查尔 价值:

julia> 'A' < 'a'
true

julia> 'A' <= 'a' <= 'Z'
false

julia>'A'<='X'<='Z'
真的

朱莉娅>'x'-'a'
23

朱莉娅>'A'+1
'B':ASCII/Unicode U+0042(类别Lu:字母,大写)

字符串基础

字符串文字由双引号或三双引号(不是单引号)分隔:

julia> str = "Hello, world.\n"
"Hello, world.\n"

julia> """Contains "quote" characters"""
"Contains \"quote\" characters"

字符串中的长行可以通过在换行符前面加上反斜杠(\):

julia> "This is a long \
       line"
"This is a long line"

如果要从字符串中提取字符,请将其编入索引:

julia> str[begin]
'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)

julia> str[1]
'H': ASCII/Unicode U+0048 (category Lu: Letter, uppercase)

julia> str[6]
',': ASCII/Unicode U+002C (category Po: Punctuation, other)

julia> str[end]
'\n': ASCII/Unicode U+000A (category Cc: Other, control)

许多Julia对象,包括字符串,都可以用整数索引。 第一个元素(字符串的第一个字符)的索引由 firstindex(str),以及最后一个元素(字符)的索引 lastindex(str). 关键词 開始啦。结束 可以在索引操作中使用,分别作为给定维度上的第一个和最后一个索引的简写。 与Julia中的大多数索引一样,字符串索引是基于1的: 第一索引 总是回来 1 对于任何 抽象字符串. 然而,我们将在下面看到, lastindex(str) is_not_一般与 长度(str) 对于一个字符串,因为一些Unicode字符可以占用多个"代码单位"。

您可以执行算术和其他操作 结束,就像正常值一样:

julia> str[end-1]
'.': ASCII/Unicode U+002E (category Po: Punctuation, other)

julia> str[end÷2]
' ': ASCII/Unicode U+0020 (category Zs: Separator, space)

使用小于 開始啦。 (1)或大于 结束 引发错误:

julia> str[begin-1]
ERROR: BoundsError: attempt to access 14-codeunit String at index [0]
[...]

julia> str[end+1]
ERROR: BoundsError: attempt to access 14-codeunit String at index [15]
[...]

您还可以使用范围索引提取子字符串:

julia> str[4:9]
"lo, wo"

请注意,表达式 str[k]str[k:k] 不要给出相同的结果:

julia> str[6]
',': ASCII/Unicode U+002C (category Po: Punctuation, other)

julia> str[6:6]
","

前者是类型的单个字符值 查尔,而后者是恰好只包含单个字符的字符串值。 在朱莉娅,这些是非常不同的事情。

范围索引会复制原始字符串的选定部分。 或者,可以使用类型将视图创建为字符串 子字符串. 更简单地说,使用 @意见代码块上的宏将所有字符串切片转换为子字符串。 例如:

julia> str = "long string"
"long string"

julia> substr = SubString(str, 1, 4)
"long"

julia> typeof(substr)
SubString{String}

julia> @views typeof(str[1:4]) # @views converts slices to SubStrings
SubString{String}

几个标准功能,如 砍;砍, chomp条带返回a 子字符串.

Unicode和UTF-8

Julia完全支持Unicode字符和字符串。 作为 上面讨论,在字符字面量中,Unicode码位可以使用Unicode表示 \u\U 转义序列,以及所有的标准c转义序列。 这些同样可以用于编写字符串文字:

julia> s = "\u2200 x \u2203 y"
"∀ x ∃ y"

这些Unicode字符是显示为转义字符还是显示为特殊字符取决于终端的区域设置及其对Unicode的支持。 字符串文字使用UTF-8编码进行编码。 UTF-8是一种可变宽度编码,这意味着并非所有字符都以相同的字节数("代码单位")进行编码。 在UTF-8中,ASCII字符-即代码点小于0X80(128)的字符-使用单个字节按ASCII编码,而代码点0x80及以上使用多个字节编码-每个字符最多四个。

Julia中的字符串索引指的是代码单位(UTF-8的=字节),即用于编码任意字符(代码点)的固定宽度构建块。 这意味着不是每个索引到一个 字符串 必须是一个字符的有效索引。 如果在这样的无效字节索引处索引到字符串,则会引发错误:

julia> s[1]
'∀': Unicode U+2200 (category Sm: Symbol, math)

julia> s[2]
ERROR: StringIndexError: invalid index [2], valid nearby indices [1]=>'∀', [4]=>' '
Stacktrace:
[...]

julia> s[3]
ERROR: StringIndexError: invalid index [3], valid nearby indices [1]=>'∀', [4]=>' '
Stacktrace:
[...]

julia> s[4]
' ': ASCII/Unicode U+0020 (category Zs: Separator, space)

在这种情况下,字符 是一个三字节字符,所以索引2和3无效,下一个字符的索引是4;下一个有效索引可以通过 下一个(s,1),以及之后的下一个索引由 下一个(s,4) 等等。

结束 始终是集合中的最后一个有效索引, 结束-1 如果倒数第二个字符是多字节,则引用无效的字节索引。

julia> s[end-1]
' ': ASCII/Unicode U+0020 (category Zs: Separator, space)

julia> s[end-2]
ERROR: StringIndexError: invalid index [9], valid nearby indices [7]=>'∃', [10]=>' '
Stacktrace:
[...]

julia> s[prevind(s, end, 2)]
'∃': Unicode U+2203 (category Sm: Symbol, math)

第一种情况有效,因为最后一个字符 y 和空间是一个字节的字符,而 结束-2 索引到 多字节表示。 这种情况的正确方法是使用 prevind(s,lastindex(s),2) 或者,如果您使用该值索引到 s 你可以写 s[prevind(s,end,2)]结束 扩展到 lastindex(s).

使用范围索引提取子字符串也需要有效的字节索引,否则会引发错误:

julia> s[1:1]
"∀"

julia> s[1:2]
ERROR: StringIndexError: invalid index [2], valid nearby indices [1]=>'∀', [4]=>' '
Stacktrace:
[...]

julia> s[1:4]
"∀ "

由于可变长度编码,字符串中的字符数(由 长度(s))并不总是与最后一个索引相同。 如果你遍历索引1通过 lastindex(s)并索引成 s,未抛出错误时返回的字符序列是包含字符串的字符序列 s. 因此 长度<=lastindex(s),因为字符串中的每个字符都必须有自己的索引。 下面是一个低效和冗长的方式来迭代的字符 s:

julia> for i = firstindex(s):lastindex(s)
           try
               println(s[i])
           catch
               # ignore the index error
           end
       end
∀

x

∃

y

空行实际上在它们上面有空格。 幸运的是,上述尴尬的习惯用法对于遍历字符串中的字符是不必要的,因为您可以将字符串用作可迭代对象,不需要异常处理:

julia> for c in s
           println(c)
       end
∀

x

∃

y

如果需要获取字符串的有效索引,可以使用 下一篇上一页函数递增/递减到下一个/上一个有效索引,如上所述。 您还可以使用 每个索引函数遍历有效的字符索引:

julia> collect(eachindex(s))
7-element Vector{Int64}:
  1
  4
  5
  6
  7
 10
 11

要访问编码的原始代码单位(UTF-8的字节),您可以使用 代码单元(s,i)函数,其中索引 i 连续运行从 1ncodeunits(s). 该 代码单位函数返回 AbstractVector{UInt8} 包装器,允许您将这些原始codeunits(字节)作为数组访问。

Julia中的字符串可以包含无效的UTF-8代码单元序列。 此约定允许将任何字节序列视为 字符串. 在这种情况下,一条规则是,当解析从左到右的代码单元序列时,由与以下位模式之一的开始相匹配的8位代码单元的最长序列(每个 x 可以是 01):

* 0xxxxxxx系列; * 110xxxx 10xxxxxx; * 1110xxxx 10xxxxxx 10xxxxxx; * 11110xxx系列 10xxxxxx 10xxxxxx 10xxxxxx; * 10xxxxxx; * 11111xxx系列.

这尤其意味着,超长和过高的代码单元序列及其前缀被视为单个无效字符而不是多个无效字符。 这个规则最好用一个例子来解释:

julia> s = "\xc0\xa0\xe2\x88\xe2|"
"\xc0\xa0\xe2\x88\xe2|"

julia> foreach(display, s)
'\xc0\xa0': [overlong] ASCII/Unicode U+0020 (category Zs: Separator, space)
'\xe2\x88': Malformed UTF-8 (category Ma: Malformed, bad data)
'\xe2': Malformed UTF-8 (category Ma: Malformed, bad data)
'|': ASCII/Unicode U+007C (category Sm: Symbol, math)

julia> isvalid.(collect(s))
4-element BitArray{1}:
 0
 0
 0
 1

julia> s2 = "\xf7\xbf\xbf\xbf"
"\U1fffff"

julia> foreach(display, s2)
'\U1fffff': Unicode U+1FFFFF (category In: Invalid, too high)

我们可以看到字符串中的前两个代码单元 s 形成空格字符的过长编码。 它无效,但在字符串中作为单个字符接受。 接下来的两个代码单元形成三字节UTF-8序列的有效开始。 然而,第五代码单元 \xe2 不是它的有效延续。 因此,代码单元3和4也被解释为该字符串中的格式错误的字符。 类似地代码单元5形成格式错误的字符,因为 | 不是它的有效延续。 最后是字符串 中二 包含一个过高的代码点。

Julia默认使用UTF-8编码,包可以添加对新编码的支持。 例如,https://github.com/JuliaStrings/LegacyStrings.jl[LegacyStrings.jl]包实现 Utf16字符串Utf32字符串 类型。 其他编码以及如何实现对它们的支持的额外讨论暂时超出了本文档的范围。 有关UTF-8编码问题的进一步讨论,请参阅下面关于 字节数组文字。 该 转码/转码函数用于在各种UTF-xx编码之间转换数据,主要用于处理外部数据和库。

连接,连接

最常见和最有用的字符串操作之一是连接:

julia> greet = "Hello"
"Hello"

julia> whom = "world"
"world"

julia> string(greet, ", ", whom, ".\n")
"Hello, world.\n"

请务必注意潜在的危险情况,例如连接无效的UTF-8字符串。 生成的字符串可能包含与输入字符串不同的字符,其字符数可能低于连接字符串的字符数之和,例如:

julia> a, b = "\xe2\x88", "\x80"
("\xe2\x88", "\x80")

julia> c = string(a, b)
"∀"

julia> collect.([a, b, c])
3-element Vector{Vector{Char}}:
 ['\xe2\x88']
 ['\x80']
 ['∀']

julia> length.([a, b, c])
3-element Vector{Int64}:
 1
 1
 1

只有无效的UTF-8字符串才会发生这种情况。 对于有效的UTF-8字符串,串联将保留字符串中的所有字符和字符串长度的附加性。

Julia还提供 *用于字符串连接:

julia> greet &ast; ", " &ast; whom &ast; ".\n"
"Hello, world.\n"

* 对于提供语言的用户来说,这似乎是一个令人惊讶的选择。 + 对于字符串连接,这种使用 * 在数学方面有先例,特别是在抽象代数方面。

在数学, + 通常表示_commutative_操作,其中操作数的顺序无关紧要。 这方面的一个例子是矩阵加法,其中 A+B==B+A 对于任何矩阵 AB 形状相同。 相比之下, * 通常表示_noncommutative_操作,其中操作数_does_的顺序很重要。 这方面的一个例子是矩阵乘法,其中一般 A*B!=B*A. 与矩阵乘法一样,字符串连接是非交换的: 问候*谁!=谁*问候. 因此, * 对于中缀字符串连接运算符来说,这是一个更自然的选择,与常见的数学用法一致。

更确切地说,所有有限长度字符串的集合_S_连同字符串连接运算符 * 表格a 免费monoid(S, *). 此集合的标识元素是空字符串, "". 每当一个自由单质不是交换的,操作通常表示为 \cdot的, *,或类似的符号,而不是 +,如所述通常意味着交换性。

插值法

但是,使用串联构造字符串可能会变得有点麻烦。 以减少对这些冗长调用的需要 字符串或重复乘法,Julia允许使用以下方法将插值到字符串文字中 $,如在Perl:

julia> greet = "Hello"; whom = "world";

julia> "$greet, $whom.\n"
"Hello, world.\n"

这更具可读性和方便性,相当于上面的字符串连接-系统将这个明显的单个字符串字面量重写到调用中 字符串(问候,",",","。\n").

后最短的完整表达式 $ 取为其值要插值到字符串中的表达式。 因此,您可以使用括号将任何表达式插值到字符串中:

julia> "1 + 2 = $(1 + 2)"
"1 + 2 = 3"

连接和字符串插值调用 字符串将对象转换为字符串形式。 然而, 字符串 实际上只是返回 印刷业,所以新类型应该将方法添加到 印刷业展览而不是 字符串.

大多数非-抽象字符串 对象被转换为与它们作为文字表达式输入的方式紧密对应的字符串:

julia> v = [1,2,3]
3-element Vector{Int64}:
 1
 2
 3

julia> "v: $v"
"v: [1, 2, 3]"

字符串是身份为 抽象字符串摘要: 值,所以这些被插值成字符串本身,无引号和无转义:

julia> c = 'x'
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)

julia> "hi, $c"
"hi, x"

包括文字 $ 在字符串文字中,用反斜杠转义它:

julia> print("I have \$100 in my account.\n")
I have $100 in my account.

三引号字符串文字

当使用三引号创建字符串时("""...""")它们有一些特殊的行为,可以用于创建更长的文本块。

首先,三引号字符串也专用于缩进最少行的级别。 这对于在缩进的代码中定义字符串很有用。 例如:

julia> str = """
           Hello,
           world.
         """
"  Hello,\n  world.\n"

在这种情况下,结束前的最后一行(空行) """ 设置缩进级别。

Dedentation级别确定为所有行中空格或制表符的最长公共起始序列,不包括开头后面的行 """ 和仅包含空格或制表符的行(包含关闭的行 """ 总是包括在内)。 然后对于所有行,不包括开头后面的文本 """,公共起始序列被删除(包括仅包含空格和制表符的行,如果它们以该序列开头),例如:

julia> """    This
         is
           a test"""
"    This\nis\n  a test"

接下来,如果开口 """ 后跟一个换行符,换行符从生成的字符串中剥离。

"""hello"""

相当于

"""
hello"""

但是

"""

hello"""

将在开头包含一个文字换行符。

换行符的剥离是在dedentation之后执行的。 例如:

julia> """
         Hello,
         world."""
"Hello,\nworld."

如果使用反斜杠删除换行符,则也会尊重dedentation:

julia> """
         Averylong\
         word"""
"Averylongword"

尾随空格保持不变。

三引号字符串文字可以包含 " 字符而不转义。

请注意,文字字符串中的换行符,无论是单引号还是三引号,都会产生换行符(LF) \n 在字符串中,即使您的编辑器使用回车 \r (CR)或CRLF组合到结束线。 要在字符串中包含CR,请使用显式转义 \r;例如,您可以输入文字字符串 "以\r\n结尾的CRLF行".

常见操作

您可以使用标准比较运算符对字符串进行字典比较:

julia> "abracadabra" < "xylophone"
true

julia> "abracadabra" == "xylophone"
false

julia> "Hello, world." != "Goodbye, world."
true

julia> "1 + 2 = 3" == "1 + 2 = $(1 + 2)"
true

你可以使用 [医芬迪斯特]和 芬德拉斯特功能:

julia> findfirst('o', "xylophone")
4

julia> findlast('o', "xylophone")
7

julia> findfirst('z', "xylophone")

您可以使用以下函数在给定偏移量处开始搜索字符 findnext芬普雷夫:

julia> findnext('o', "xylophone", 1)
4

julia> findnext('o', "xylophone", 5)
7

julia> findprev('o', "xylophone", 5)
4

julia> findnext('o', "xylophone", 8)

您可以使用 发生,发生检查字符串中是否找到子字符串的函数:

julia> occursin("world", "Hello, world.")
true

julia> occursin("o", "Xylophon")
true

julia> occursin("a", "Xylophon")
false

julia> occursin('o', "Xylophon")
true

最后一个例子表明 发生,发生也可以寻找一个字符字面量。

另外两个方便的字符串函数是 重复一遍加入:

julia> repeat(".:Z:.", 10)
".:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:."

julia> join(["apples", "bananas", "pineapples"], ", ", " and ")
"apples, bananas and pineapples"

其他一些有用的功能 include:

* firstindex(str)给出可用于索引到的最小(字节)索引 斯特拉 (对于字符串总是1,对于其他容器不一定如此)。 * lastindex(str)给出可用于索引到的最大(字节)索引 斯特拉. * 长度(str)中的字符数 斯特拉. * 长度(str,i,j)有效字符索引的数目 斯特拉ij. * ncodeunits(str)数目https://en.wikipedia.org/wiki/Character_encoding#Terminology字符串中的[代码单位]。 * codeunit(str,i)给出字符串中的代码单位值 斯特拉 在索引 i. * 这个数字(str,i)给定一个任意索引到一个字符串中,找到索引指向的字符的第一个索引。 * nextind(str,i,n=1)找到开始 n索引后开始的字符 i. * prevind(str,i,n=1)找到开始 n索引前开始的字符 i.

非标准字符串文字

在某些情况下,当您想要构造字符串或使用字符串语义时,但标准字符串构造的行为并不完全是所需的。 对于这类情况,Julia提供了非标准的字符串文字。 非标准字符串字面量看起来像常规的双引号字符串字面量,但立即以标识符作为前缀,并且可能与普通字符串字面量的行为不同。

正则表达式, 字节数组文字,以及 版本号文字,如下所述,是非标准字符串文字的一些示例。 用户和包也可以定义新的非标准字符串文字。 更多文件载于 元编程部分。

正则表达式

有时你不是在寻找一个确切的字符串,而是一个特定的_pattern_。 例如,假设您尝试从大型文本文件中提取单个日期。 你不知道那个日期是什么(这就是为什么你正在寻找它),但你知道它会看起来像 YYYY-MM-DD. 正则表达式允许您指定这些模式并搜索它们。

Julia使用Perl兼容正则表达式(regexes)的版本2,由https://www.pcre.org/[PCRE]图书馆(见https://www.pcre.org/current/doc/html/pcre2syntax.html[PCRE2语法说明]了解更多详情)。 正则表达式以两种方式与字符串相关:明显的连接是正则表达式用于查找字符串中的规则模式;另一个连接是正则表达式本身作为字符串输入,解析为状态机, 在Julia中,正则表达式是使用非标准字符串文字输入的,这些文字以以下开头的各种标识符为前缀 r. 没有打开任何选项的最基本的正则表达式字面量只是使用 r"。..":

julia> re = r"^\s&ast;(?:#|$)"
r"^\s&ast;(?:#|$)"

julia> typeof(re)
Regex

要检查正则表达式是否与字符串匹配,请使用 发生,发生:

julia> occursin(r"^\s&ast;(?:#|$)", "not a comment")
false

julia> occursin(r"^\s&ast;(?:#|$)", "# a comment")
true

正如人们可以看到这里, 发生,发生简单地返回true或false,指示字符串中是否出现给定正则表达式的匹配。 然而,通常情况下,人们不仅想知道一个字符串是否匹配,而且还想知道它是否匹配。 要捕获有关匹配的此信息,请使用 比赛函数代替:

julia> match(r"^\s&ast;(?:#|$)", "not a comment")

julia> match(r"^\s&ast;(?:#|$)", "# a comment")
RegexMatch("#")

如果正则表达式与给定字符串不匹配, 比赛回报 什么都没有--在交互提示符下不打印任何内容的特殊值。 除了不打印之外,它是一个完全正常的值,您可以通过编程方式对其进行测试:

m = match(r"^\s&ast;(?:#|$)", line)
if m === nothing
    println("not a comment")
else
    println("blank or comment")
end

如果正则表达式匹配,则返回的值由 比赛是一个 正则表达式对象。 这些对象记录表达式的匹配方式,包括模式匹配的子字符串和任何捕获的子字符串(如果有的话)。 此示例仅捕获匹配的子字符串部分,但也许我们希望捕获注释字符之后的任何非空白文本。 我们可以做到以下几点:

julia> m = match(r"^\s&ast;(?:#\s&ast;(.&ast;?)\s&ast;$)", "# a comment ")
RegexMatch("# a comment ", 1="a comment")

打电话时 比赛,您可以选择指定开始搜索的索引。 例如:

julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",1)
RegexMatch("1")

julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",6)
RegexMatch("2")

julia>m=匹配(r"[0-9]","aaaa1aaaa2aaa3",11)
RegexMatch("3")

您可以从a中提取以下信息 正则表达式匹配 对象:

*匹配的整个子字符串: m.比赛 *捕获的子字符串作为字符串数组: m.捕获 *整个比赛开始的偏移量: m.偏移量 *捕获的子串的偏移量作为向量: m.偏移量

用于当捕获不匹配时,而不是子字符串, m.捕获 包含 什么都没有 在那个位置,和 m.偏移量 具有零偏移量(回想一下Julia中的索引是基于1的,因此字符串中的零偏移量无效)。 这里有一对有点做作的例子:

julia> m = match(r"(a|b)(c)?(d)", "acd")
RegexMatch("acd", 1="a", 2="c", 3="d")

julia> m.match
"acd"

julia> m.captures
3-element Vector{Union{Nothing, SubString{String}}}:
 "a"
 "c"
 "d"

julia> m.offset
1

julia> m.offsets
3-element Vector{Int64}:
 1
 2
 3

julia> m = match(r"(a|b)(c)?(d)", "ad")
RegexMatch("ad", 1="a", 2=nothing, 3="d")

julia> m.match
"ad"

julia> m.captures
3-element Vector{Union{Nothing, SubString{String}}}:
 "a"
 nothing
 "d"

julia> m.offset
1

julia> m.offsets
3-element Vector{Int64}:
 1
 0
 2

将捕获作为数组返回是很方便的,这样就可以使用解构语法将它们绑定到局部变量。 为方便起见, 正则表达式匹配 对象实现迭代器方法,通过 捕获 字段,这样就可以直接析构match对象了:

julia> first, second, third = m; first
"a"

捕获也可以通过索引 正则表达式 具有捕获组的编号或名称的对象:

julia> m=match(r"(?<hour>\d+):(?<minute>\d+)","12:45")
RegexMatch("12:45", hour="12", minute="45")

julia> m[:minute]
"45"

julia> m[2]
"45"

使用时,可以在替换字符串中引用捕获 更换/更换通过使用 \n 引用第n个捕获组并在替换字符串前面加上 s. 捕获组0是指整个匹配对象。 命名的捕获组可以在替换中引用 \g<组名>. 例如:

julia> replace("first second", r"(\w+) (?<agroup>\w+)" => s"\g<agroup> \1")
"second first"

编号的捕获组也可以引用为 \g<n> 对于消歧,如在:

julia> replace("a", r"." => s"\g<0>1")
"a1"

您可以通过标志的某种组合来修改正则表达式的行为 i, m, s,而 x 结束后的双引号。 这些标志与它们在Perl中具有相同的含义,正如本文摘录的https://perldoc.perl.org/perlre#Modifiers[页码]:

i   Do case-insensitive pattern matching.

    If locale matching rules are in effect, the case map is taken
    from the current locale for code points less than 255, and
    from Unicode rules for larger code points. However, matches
    that would cross the Unicode rules/non-Unicode rules boundary
    (ords 255/256) will not succeed.

m   Treat string as multiple lines. That is, change "^" and "$"
    from matching the start or end of the string to matching the
    start or end of any line anywhere within the string.

s   Treat string as single line. That is, change "." to match any
    character whatsoever, even a newline, which normally it would
    not match.

    Used together, as r""ms, they let the "." match any character
    whatsoever, while still allowing "^" and "$" to match,
    respectively, just after and just before newlines within the
    string.

x   Tells the regular expression parser to ignore most whitespace
    that is neither backslashed nor within a character class. You
    can use this to break up your regular expression into
    (slightly) more readable parts. The '#' character is also
    treated as a metacharacter introducing a comment, just as in
    ordinary code.

例如,下面的正则表达式打开了所有三个标志:

julia> r"a+.&ast;b+.&ast;d$"ism
r"a+.&ast;b+.&ast;d$"ims

julia> match(r"a+.&ast;b+.&ast;d$"ism, "Goodbye,\nOh, angry,\nBad world\n")
RegexMatch("angry,\nBad world")

r"。.." 字面量是在没有插值和非缩放的情况下构造的(引号除外 " 其中仍然必须逃脱)。 下面是一个示例,显示了与标准字符串文字的区别:

julia> x = 10
10

julia> r"$x"
r"$x"

julia> "$x"
"10"

julia> r"\x"
r"\x"

julia> "\x"
ERROR: syntax: invalid escape sequence

三引号正则表达式字符串,形式 r"""。..""",也被支持(并且对于包含引号或换行符的正则表达式可能很方便)。

正则表达式() 构造函数可用于以编程方式创建有效的正则表达式字符串。 这允许在构造正则表达式字符串时使用字符串变量的内容和其他字符串操作。 上面的任何正则表达式代码都可以在单个字符串参数中使用 正则表达式(). 以下是一些例子:

julia> using Dates

julia> d = Date(1962,7,10)
1962-07-10

julia> regex_d = Regex("Day " &ast; string(day(d)))
r"Day 10"

julia> match(regex_d, "It happened on Day 10")
RegexMatch("Day 10")

julia> name = "Jon"
"Jon"

julia> regex_name = Regex("[\"( ]\\Q$name\\E[\") ]")  # interpolate value of name
r"[\"( ]\QJon\E[\") ]"

julia>匹配(regex_name,"Jon")
RegexMatch("乔恩")

julia>match(regex_name,"[Jon]")===nothing
真的

注意使用 \Q...\E 转义序列。 之间的所有字符 \Q\E 被解释为字面字符。 这对于匹配本来是正则表达式元字符的字符很方便。 但是,将此功能与字符串插值一起使用时需要小心,因为插值字符串本身可能包含 \E 序列,意外终止字面匹配。 在包含在正则表达式中之前,需要对用户输入进行消毒。

字节数组文字

另一个有用的非标准字符串字面量是字节数组字符串字面量: b"。..". 这种形式允许您使用字符串表示法来表示只读字面量字节数组-即 UInt8值。 这些对象的类型是 代码单位{UInt8, String}. 字节数组字面量的规则如下:

*ASCII字符和ASCII转义产生单个字节。 * \x 和八进制转义序列产生转义值对应的_byte_。 *Unicode转义序列产生一个字节序列,以UTF-8编码该代码点。

这些规则之间有一些重叠,因为 \x 前两条规则都涵盖了小于0x80(128)的八进制转义,但在这里这些规则一致。 总之,这些规则允许人们轻松地使用ASCII字符,任意字节值和UTF-8序列来生成字节数组。 这是一个使用所有三个的例子:

julia> b"DATA\xff\u2200"
8-element Base.CodeUnits{UInt8, String}:
 0x44
 0x41
 0x54
 0x41
 0xff
 0xe2
 0x88
 0x80

ASCII字符串"DATA"对应于字节68,65,84,65。 \xff 产生单字节255。 Unicode转义 \u2200 以UTF-8编码为三个字节226、136、128。 请注意,生成的字节数组不对应于有效的UTF-8字符串:

julia> isvalid("DATA\xff\u2200")
false

如前所述 代码单位{UInt8, String} 类型的行为就像只读数组 UInt8 如果你需要一个标准的矢量,你可以使用 向量{UInt8}:

julia> x = b"123"
3-element Base.CodeUnits{UInt8, String}:
 0x31
 0x32
 0x33

julia> x[1]
0x31

julia> x[1] = 0x32
ERROR: CanonicalIndexError: setindex! not defined for Base.CodeUnits{UInt8, String}
[...]

julia> Vector{UInt8}(x)
3-element Vector{UInt8}:
 0x31
 0x32
 0x33

还要观察两者之间的显着区别。 \xff\uff:前一个转义序列编码_byte255_,后一个转义序列表示_CODE点255_,在UTF-8中编码为两个字节:

julia> b"\xff"
1-element Base.CodeUnits{UInt8, String}:
 0xff

julia> b"\uff"
2-element Base.CodeUnits{UInt8, String}:
 0xc3
 0xbf

字符文字使用相同的行为。

对于代码点小于 \u80,恰好每个码点的UTF-8编码只是对应产生的单字节 \x 逃逸,所以区分可以安全地忽略。 为了逃跑 \x80 通过 \xff 相比于 \u80 通过 \uff 但是,有一个主要的区别:前者转义所有编码的单个字节,除非后面跟着非常具体的延续字节,否则不会形成有效的UTF-8数据,而后者转义都表示具有两字节编码的Unicode代码点。

如果这一切都非常混乱,请尝试阅读https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/["绝对最小值每个软件开发人员绝对,肯定必须了解Unicode和字符集"]。 这是对Unicode和UTF-8的一个很好的介绍,可能有助于减轻对此事的一些混淆。

版本号文字

版本号可以很容易地用形式的非标准字符串文字来表示 v"。..". 版本号文字创建 版本号符合https://semver.org/spec/v2.0.0-rc.2.html[语义版本控制2.0.0-rc2],因此由主要、次要和补丁数字值组成,然后是预发布和构建字母数字注释。 例如, v"0.2.1-rc1+win64" 被分解成主要版本 0,次要版本 2,补丁版本 1,预发布 rc1 和建造 win64的. 当输入版本文字时,除了主要版本号之外的所有内容都是可选的,因此例如 v"0.2" 相当于 v"0.2.0" (带有空的预发布/构建注释), v"2" 相当于 v"2.0.0",等等。

版本号 对象对于轻松正确地比较两个(或更多)版本非常有用。 例如,常数 版本持有Julia版本号为 版本号 对象,因此可以使用简单的语句定义一些特定于版本的行为:

if v"0.2" <= VERSION < v"0.3-"
    # do something specific to 0.2 release series
end

请注意,在上面的示例中,非标准版本号 v"0.3-" 被使用,带有尾随 -:这个符号是标准的Julia扩展,它用来表示一个低于任何一个版本的版本 0.3 发布,包括所有的预发布。 所以在上面的例子中,代码只能在稳定的情况下运行 0.2 版本,并将此类版本排除为 v"0.3.0-rc1". 为了还允许不稳定(即预释放) 0.2 版本,下界检查应该这样修改: v"0.2-"<=版本.

另一个非标准版本规范扩展允许使用尾随 + 表示构建版本的上限,例如 版本>v"0.2-rc1+" 可以用来表示上面的任何版本 0.2-rc1 和它的任何构建:它会返回 错误 对于版本 v"0.2-rc1+win64"真的v"0.2-rc2".

在比较中使用这种特殊版本是很好的做法(特别是尾随版本) - 应该总是在上界使用,除非有充分的理由不使用),但它们不能用作任何东西的实际版本号,因为它们在语义版本控制方案中是无效的。

除了用于 版本常数, 版本号 对象广泛应用于 Pkg,Pkg 模块,用于指定软件包版本及其依赖项。

原始字符串文字

没有插值或未缩放的原始字符串可以用形式的非标准字符串文字来表示 生"。..". 原始字符串文字创建普通 字符串 包含与输入完全相同的封闭内容的对象,没有插值或未缩放。 这对于包含使用其他语言的代码或标记的字符串很有用 $\ 作为特殊字符。

例外情况是引号仍然必须转义,例如 生"\"" 相当于 "\"". 为了能够表达所有字符串,反斜杠也必须被转义,但只有在出现在引号字符之前:

julia> println(raw"\\ \\\"")
\\ \"

请注意,前两个反斜杠在输出中逐字显示,因为它们不在引号字符之前。 但是,下一个反斜杠字符会转义后面的反斜杠,最后一个反斜杠会转义引号,因为这些反斜杠出现在引号之前。

带注释的字符串

请注意,AnnotatedStrings的API被认为是实验性的,并且可能会在Julia版本之间发生变化。

有时,能够保存与字符串区域相关的元数据是很有用的。 A 注释字符串包装另一个字符串,并允许用标记的值(:标签=>值). 所有泛型字符串操作都应用于基础字符串。 但是,在可能的情况下,样式信息会被保留。 这意味着你可以操纵一个 注释字符串--取子字符串,填充它们,将它们与其他字符串连接起来—​元数据注释将"顺其自然"。

此字符串类型是基本的 StyledStrings stdlib,它使用 :脸-标记注释以保存样式信息。

当连接一个 注释字符串,小心使用 注释字符串而不是 字符串如果你想保留字符串注释。

julia> str = Base.AnnotatedString("hello there",
               [(1:5, :word, :greeting), (7:11, :label, 1)])
"hello there"

julia> length(str)
11

julia> lpad(str, 14)
"   hello there"

julia> typeof(lpad(str, 7))
Base.AnnotatedString{String}

julia> str2 = Base.AnnotatedString(" julia", [(2:6, :face, :magenta)])
" julia"

julia> Base.annotatedstring(str, str2)
"hello there julia"

julia> str &ast; str2 == Base.annotatedstring(str, str2) # &ast;-concatenation still works
true

A的注释 注释字符串可透过 说明注释!功能。