线条
字符串是有限的字符序列。 然而,当有人问什么是符号时,真正的问题就出现了。 说英语的用户熟悉以下字符:字母’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编码,有一个功能 '转码'。)
-
所有字符串类型都是抽象类型’AbstractString`的子类型,外部包定义了`AbstractString’的其他子类型(例如,对于其他编码)。 当定义一个需要字符串参数的函数时,您应该将类型声明为`AbstractString`,以便它接受任何字符串类型。
-
就像在C和Java中一样,但与大多数动态语言不同,Julia有一种非常流行的表示单个字符的类型,称为 'AbstractChar'。 嵌入式子类型 'Char'是一种32位基元类型,可以表示任何Unicode字符(并且基于UTF-8编码)。
-
与Java中一样,字符串是不可变的:AbstractString对象的值不能更改。 要创建另一个字符串值,您需要从其他字符串的部分构建一个新字符串。
-
从概念上讲,字符串是从索引到字符的_particle function_:对于某些索引值,不返回字符值,但发生异常。 这允许您通过编码表示形式的字节索引来索引字符串,而不是通过字符索引来索引字符串,这对于Unicode字符串的字节数可变的编码来说无法高效而简
符号
值’Char’表示单个字符:它只是一个32位原始类型,具有特殊的文字表示和相应的算术行为,可以转换为表示https://en.wikipedia.org/wiki/Code_point [Unicode字符代码]。 (Julia包可以定义’AbstractChar’的其他子类型,例如,为其他人优化操作https://en.wikipedia.org/wiki/Character_encoding [文本编码]。)这就是`Char`值的输入和显示方式(请注意,字符文字由单引号分隔,而不是双引号):
julia> c = 'x'
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)
julia> typeof(c)
Char
'Char’的值可以很容易地转换为它的整数值,即字符代码。
julia> c = Int('x')
120
julia> typeof(c)
Int64
在32位架构中,功能 'typeof(c’将具有类型 'Int32'。 整数值可以很容易地转换回’Char’类型。
julia> Char(120)
'x': ASCII/Unicode U+0078 (category Ll: Letter, lowercase)
并非所有整数值都是有效的Unicode字符代码,但为了提高性能’Char’类型转换不会检查每个字符值的有效性。 若要验证每个转换的值是否为有效的字符代码,请使用函数 'isvalid'。
julia> Char(0x110000)
'\U110000': Unicode U+110000 (category In: Invalid, too high)
julia> isvalid(Char, 0x110000)
false
在撰写本文时,有效的Unicode字符代码是’U+0000'’U+D7FF’和’U+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
您可以使用`Char`值执行比较和有限数量的算术运算。
julia> 'A' < 'a'
true
julia> 'A' <= 'a' <= 'Z'
false
julia> 'A' <= 'X' <= 'Z'
true
julia> 'x' - 'a'
23
julia> 'A' + 1
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)
使用字符串的基础知识
字符串文字由双引号或三双引号(不是单引号)分隔。
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)
朱莉娅>str[结束]
'\n':ASCII/Unicode U+000A(类别Cc:其他,控制)
许多Julia对象,包括字符串,都可以使用整数进行索引。 函数返回第一个元素(字符串的第一个字符)的索引 'firstindex(str)`,最后一个元素(字符)的索引是一个函数 'lastindex(str’。 关键字’begin’和’end’可以在索引操作中分别作为给定维度中第一个和最后一个索引的缩写使用。 字符串索引,就像Julia中的大多数索引一样,从1开始。 'Firstindex’函数始终为任何`AbstractString`对象返回`1'。 但是,正如我们将在下面看到的,`lastindex(str)`函数通常与字符串的`length(str)`函数不同,因为一些Unicode字符可能占用几个代码单元。
带关键字 `end'您可以像使用常规值一样执行算术和其他操作。
julia> str[end-1]
'.': ASCII/Unicode U+002E (category Po: Punctuation, other)
julia> str[end÷2]
' ': ASCII/Unicode U+0020 (category Zs: Separator, space)
使用小于关键字`begin`(1
)或大于关键字`end`的索引会导致错误。
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]
","
第一个是`Char’类型的单字符值,第二个是只包含一个字符的字符串值。 这些在朱莉娅是完全不同的事情。
julia> str = "long string"
"long string"
julia>substr=子字符串(str,1,4)
"长"
朱莉娅>typeof(substr)
子字符串{String}
julia>@views typeof(str[1:4])#@views将片段转换为子字符串
子字符串{String}
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的字节),标准的固定宽度块,用于编码任意字符(字符代码)。 这意味着并非每个字符串索引(`String')都一定是字符的有效索引。 如果使用这样的无效字节索引对字符串进行索引,则会返回错误。
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。 下一个有效索引可以使用函数计算 'nextind(s,1)
,接着使用函数`nextind(s,4)`等等。
由于’end’始终是集合中的最后一个有效索引,因此,如果倒数第二个字符是多字节,则`end-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`和空格是单字节字符,而`end-2`索引多字节表示形式`∃'的中间。 这里的正确方法是使用函数’prevent(s,lastindex(s),2)或者,如果您在`s`中使用此值进行索引,则可以编写`s[prevent(s,end,2)]
,并且`end`扩展为函数`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]
"∀ "
由于可变长度编码,字符串中的字符数(使用该方法设置 'length(s))并不总是与最后一个索引匹配。 如果你遍历索引从第一个到最后一个('lastindex(s))和索引`s`,在没有错误的情况下返回的字符序列将是组成字符串`s`的字符序列。 因此,'length(s)<=lastindex(s)`,因为字符串中的每个字符都必须有自己的索引。 下面是一种低效且重载的方式来迭代字符串`s`的字符。
julia> for i = firstindex(s):lastindex(s)
try
println(s[i])
catch
# Игнорировать ошибку индекса
end
end
∀
x
∃
y
空行中实际上有空格。 幸运的是,上述不方便的选项对于迭代字符串中的字符不是必需的,因为您可以简单地将字符串用作不需要异常处理的可迭代对象。
julia> for c in s
println(c)
end
∀
x
∃
y
如果需要获取行的有效索引,可以使用以下函数 'nextind'和 'prevent'将值增加或减少到下一个或上一个有效索引,如上所述。 您也可以使用该功能 `eachindex'用于迭代有效的字符索引。
julia> collect(eachindex(s))
7-element Vector{Int64}:
1
4
5
6
7
10
11
要访问原始代码单位(UTF-8的字节)编码,可以使用该函数 'codeunit(s,i),其中索引’i`从'1’顺序执行到 'ncodeunits(s)。 功能
codeunits(s)'
返回shell'+AbstractVector{UInt8}+,它允许您将这些原始代码单元(字节)作为数组访问。
Julia中的字符串可能包含无效的UTF-8代码序列。 此约定允许您将任何字节序列视为字符串(String')。 在这种情况下,以下规则适用:当从左到右分析代码单元序列时,字符由最长的8位代码单元序列形成,该序列与以下位模式之一的开始重合(每个`x`可以具有值`0`或`1
)。
-
`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的单位形成一个不正确的字符,因为`/`不是其有效的延续。 结果,字符串’s2’包含一个顺序过高的字符代码。
Julia默认使用UTF-8编码,可以使用包添加对新编码的支持。 例如,包https://github.com/JuliaStrings/LegacyStrings.jl [LegacyStrings.jl]实现’UTF16String’和`UTF32String’类型。 其他编码的额外讨论以及如何实现它们的支持仍然超出了本文档的范围。 有关UTF-8编码的更多信息,请参阅下面关于 字节数组文字。 功能 'transcode'旨在在不同的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 * ", " * whom * ".\n"
"Hello, world.\n"
对于使用`+方法连接字符串的语言的用户来说,似乎
*方法的选择是出乎意料的,但是使用
*`在数学中有先例,特别是在抽象代数中。
在数学中,'+'通常表示_commutative_操作,其中操作数的顺序无关紧要。 一个例子是矩阵加法,其中`A+B==B+A’用于具有相同形状的任何矩阵`A`和`B`。 恰恰相反, *
它通常表示非交换操作,其中操作数的顺序具有值。 一个例子是矩阵乘法,其中在一般情况下`A*B!=B*A'。 与矩阵乘法的情况一样,字符串串联是非交换的:'hello*who!=谁*问候'。 因此``*'方法对于字符串连接的中缀运算符来说是更自然的选择,这对应于普遍接受的数学用法。
更确切地说,有限长度_S_的所有字符串的集合,连同字符串连接运算符`*, 表格https://en.wikipedia.org/wiki/Free_monoid [免费monoid](S, `*
). 该集合的中性元素是空字符串`""`。 当一个自由单质是非交换时,操作通常表示为'\cdot`, *
或类似的字符,而不是'+',如前所述,通常意味着交换性。
插值法
使用串联构建字符串可能会成为一个相当繁重的过程。 以减少对详细函数调用的需求 `string'或重复乘法运算,Julia允许您使用字面值'$'执行字符串字面值的插值,就像在Perl中一样。
julia> greet = "Hello"; whom = "world";
julia> "$greet, $whom.\n"
"Hello, world.\n"
这是一个更具可读性和权宜之计的功能,相当于上面描述的字符串连接,-系统将这个看似单一的字符串文字重写到call`string(greet,",",who,"中。\n")'。
在`$`之后最短的完整表达式被接受为其值应插值到字符串中的表达式。 因此,您可以使用括号将任何表达式插值到字符串中。
julia> "1 + 2 = $(1 + 2)"
"1 + 2 = 3"
连接和字符串插值都调用该函数 `string'用于将对象转换为字符串形式。 但是,'string’函数实际上只是返回函数的输出 'print',所以新类型应该为函数添加方法 '打印'或方法 'show'而不是’string’函数。
大多数没有AbstractString类型的对象将转换为与作为字面表达式输入它们的类型完全匹配的字符串。
julia> v = [1,2,3]
3-element Vector{Int64}:
1
2
3
julia> "v: $v"
"v: [1, 2, 3]"
功能 'string'是值`AbstractString`和`AbstractChar`的标识符,因此它们被插入字符串本身,没有引号或转义。
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"
在这种情况下,结束`"""`之前的最后一行(空)设置缩进级别。
对齐级别定义为所有行中空格或制表符的最长公共初始序列,不包括开头三引号(""“)后面的行和仅包含空格或制表符的行(始终包括包含结尾三引号(”"“)的行)。 然后,对于所有行,不包括开头三引号(”""
)后面的文本,一般的初始序列被删除(包括仅包含空格和制表符的行,如果它们以该序列开头),例如:
julia> """ This
is
a test"""
" This\nis\n a test"
接下来,如果开头的三引号("""
)后跟一个换行符,它将从生成的字符串中删除。
"""hello"""
相当于
"""
hello"""
但是
"""
hello"""
它将在开头包含一个文字换行符。
对齐后进行换行排除。 例如:
julia> """
Hello,
world."""
"Hello,\nworld."
如果使用反斜杠删除新行,对齐也将被考虑在内。
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
您可以使用以下函数搜索特定字符的索引 'findfirst`和 'findlast`:
julia> findfirst('o', "xylophone")
4
julia> findlast('o', "xylophone")
7
julia> findfirst('z', "xylophone")
您可以使用以下函数从给定偏移量开始搜索字符 'findnext'和 'findprev'。
julia> findnext('o', "xylophone", 1)
4
julia> findnext('o', "xylophone", 5)
7
julia> findprev('o', "xylophone", 5)
4
julia> findnext('o', "xylophone", 8)
您可以使用该功能 `ocsin'检查字符串中是否找到子字符串。
julia> occursin("world", "Hello, world.")
true
julia> occursin("o", "Xylophon")
true
julia> occursin("a", "Xylophon")
false
julia> occursin('o', "Xylophon")
true
最后一个例子显示了函数 'occussin'也可以搜索字符文字。
julia> repeat(".:Z:.", 10)
".:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:..:Z:."
julia>加入(["苹果","香蕉","菠萝"],",","和")
"苹果,香蕉和菠萝"
下面列出了一些其他有用的功能。
-
'firstindex(str’给出可用于索引到`str`的最小(字节)索引(对于字符串总是1,对于其他容器不一定为true)。
-
`lastindex(str)'给出可用于索引到`str`的最大(字节)索引。
-
length(str)
'str’中的字符数。 -
'length(str,i,j)``str`中从`i`到`j`的有效字符索引数。
-
`ncodeunits(str)'数量https://en.wikipedia.org/wiki/Character_encoding#Terminology字符串中的[代码单位]。
-
'codeunit(str,i)`在索引`i`处给出字符串`str’中的代码单元值。
-
`thisind(str,i)'给定一个任意索引到一个字符串中,找到索引指向的字符的第一个索引。
-
'nextind(str,i,n=1)`查找索引`i`之后开始的第`n`个字符的开头。
-
prevind(str,i,n=1)
查找索引`i’之前开始的第`n`个字符的开头。
正则表达式
有时你不是在寻找一个确切的字符串,而是寻找一个特定的模式。 例如,假设您试图从大型文本文件中获取单个日期。 你不知道这个日期是什么(这就是为什么你要寻找它),但你知道它会看起来像这样:`YYYY-MM-DD'。 正则表达式允许您设置这些模式并搜索它们。
库提供的Perl兼容正则表达式(regex)版本2在Julia中可用。 https://www.pcre.org /[PCRE](可以找到PCRE2语法的描述https://www.pcre.org/current/doc/html/pcre2syntax.html [这里])。 正则表达式以两种方式与字符串相关:明显的连接是正则表达式用于查找字符串中的规则模式;另一个连接是正则表达式本身作为字符串输入,解析为有限 在Julia中,正则表达式是使用非标准字符串文字引入的,这些文字以"r"开头的各种标识符为前缀。 没有启用功能的最简单正则表达式字面量只需使用'r"。.."`.
julia> re = r"^\s*(?:#|$)"
r"^\s*(?:#|$)"
julia> typeof(re)
Regex
若要检查正则表达式是否与字符串匹配,请使用函数 '发生'。
julia> occursin(r"^\s*(?:#|$)", "not a comment")
false
julia> occursin(r"^\s*(?:#|$)", "# a comment")
true
正如你所看到的,功能 `occurrin'只返回true或false值,指示字符串是否与指定的正则表达式匹配。 但是,不仅要知道字符串是否匹配,还要知道它是如何匹配的。 要记录此匹配信息,使用函数 '匹配'。
julia> match(r"^\s*(?:#|$)", "not a comment")
julia> match(r"^\s*(?:#|$)", "# a comment")
RegexMatch("#")
m = match(r"^\s*(?:#|$)", line)
if m === nothing
println("not a comment")
else
println("blank or comment")
end
如果正则表达式匹配,则函数返回的值为 'match',是一个对象 'RegexMatch'。 这些对象注册表达式的匹配,包括与模板匹配的子字符串,以及所有找到的子字符串(如果有的话)。 在此示例中,只写入与子字符串匹配的部分,但您可能需要在注释字符后面写入任何非空文本。 您可以执行以下操作。
julia> m = match(r"^\s*(?:#\s*(.*?)\s*$)", "# a comment ")
RegexMatch("# a comment ", 1="a comment")
调用函数时 `match'您可以指定搜索开始的索引。 例如:
julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",1)
RegexMatch("1")
julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",6)
RegexMatch("2")
julia> m = match(r"[0-9]","aaaa1aaaa2aaaa3",11)
RegexMatch("3")
可以从`RegexMatch’对象中提取以下信息。
-
整个匹配的子字符串’m.match`
-
将子字符串记录为字符串数组’m.captures`
-
整个匹配开始的偏移量’m.offset`
-
作为向量的记录子字符串的偏移量:'m.偏移量`
在记录不匹配的情况下,而不是子字符串,记录('m.captures`)在此位置不包含任何内容(nothing
),偏移量(m.offsets
)为零(回想一下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.捕获
3元素向量{Union{Nothing, SubString{String}}}:
"一个"
"c"
"d"
julia>m.偏移量
1
朱莉娅>m.偏移
3元素向量{Int64}:
1
2
3
julia>m=match(r"(a|b)(c)?(d)","广告")
RegexMatch("ad",1="a",2=nothing,3="d")
朱莉娅>m.匹配
"广告"
julia>m.捕获
3元素向量{Union{Nothing, SubString{String}}}:
"一个"
什么都没有
"d"
julia>m.偏移量
1
朱莉娅>m.偏移
3元素向量{Int64}:
1
0
2
当记录作为数组返回时很方便,因此您可以使用析构语法将它们绑定到局部变量。 'RegexMatch’对象实现了传递给’captures’字段的迭代器方法,因此您可以直接析构匹配的对象。
julia> first, second, third = m; first
"a"
也可以通过使用记录组编号或名称索引`RegexMatch`对象来访问记录。
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"
使用该函数时,可以在替换字符串中引用该记录 'replace'通过使用'\n’来引用第n个记录组,并添加`s’作为替换字符串的前缀。 记录组0指的是整个匹配对象。 命名的记录组可以使用`\g<groupname>'在替换中引用。 例如:
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 [Perl正则表达式手册页]。
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 '#символ ' также treated as a metacharacter introducing a comment, just as in ordinary code.
例如,在下面的正则表达式中,所有三个标志都启用。
julia> r"a+.*b+.*d$"ism
r"a+.*b+.*d$"ims
julia> match(r"a+.*b+.*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"
朱莉娅>r"\x"
r"\x"
朱莉娅>"\x"
错误:语法:无效转义序列
带有三引号的正则表达式字符串,格式为'r"""。..还支持"""`(对于包含引号或换行符的正则表达式可能很有用)。
要以编程方式创建有效的正则表达式字符串,可以使用`Regex()构造函数。`. 在这种情况下,您可以在构造正则表达式字符串时使用字符串变量和其他字符串操作的内容。 上述任何正则表达式代码都可以在`Regex()`构造函数的单个字符串参数中使用。 以下是一些例子:
julia> using Dates
julia> d = Date(1962,7,10)
1962-07-10
julia> regex_d = Regex("Day " * 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[\") ]") # Интерполяция значения имени
r"[\"( ]\QJon\E[\") ]"
julia> match(regex_name, " Jon ")
RegexMatch(" Jon ")
julia> match(regex_name, "[Jon]") === nothing
true
注意转义序列`\Q的使用。..\E'。 \Q`和
\E’之间的所有字符都被解释为文字字符。 这对于匹配原本是正则表达式元字符的字符很有用。 但是,当将此函数与字符串插值一起使用时,您应该小心,因为插值的字符串本身可能包含序列'\E',这将意外地停止匹配文字。 用户输入的数据必须在包含在正则表达式中之前进行消毒。
字节数组的字面量
另一个有用的非标准字符串字面量是字节数组字符串字面量’b"。..". 这种形式允许您使用字符串表示法来表示只读字节的字面数组,即值数组。 'UInt8'。 这些对象是’CodeUnits’类型{UInt8, String}
. 以下规则适用于字节数组的字面值。
-
ASCII字符和ASCII转义字符创建单个字节。
-
字符'\x’和八进制转义序列创建一个与转义值对应的字节。
-
Unicode转义序列创建以UTF-8编码给定字符代码的字节序列。
这些规则彼此部分重复,因为小于0x80(128)的`\x`和八进制转义序列的行为属于前两个规则,但在这里这些规则是一致的。 这些规则的组合使得使用ASCII字符、任意字节值和UTF-8序列创建字节数组变得容易。 以下是使用所有三个规则的示例。
julia> b"DATA\xff\u2200"
8-element Base.CodeUnits{UInt8, String}:
0x44
0x41
0x54
0x41
0xff
0xe2
0x88
0x80
ASCII数据串对应于字节68、65、84、65。 '\xff’输出一个字节255。 Unicode转义序列'\u2200’以UTF-8编码为字节226,136,128。 请注意,生成的字节数组与有效的UTF-8字符串不匹配。
julia> isvalid("DATA\xff\u2200")
false
如前所述,类型为’CodeUnits{UInt8, String}'行为像一个只读数组’UInt8`,如果你需要一个标准向量,你可以使用'Vector{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`之间的显着差异:第一个序列编码255_字节,而第二个序列表示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字符 用双字节编码。
如果这一切完全不清楚,请尝试阅读文档。 The Absolute Minimum Every Software Developer Absolute,Positively Must Know About Unicode and Character Sets(每个软件开发人员都应该知道的关于Unicode和字符集的绝对最小值)。 这是一篇关于Unicode和UTF-8的很好的介绍性文章,可以帮助您解决这个问题。
版本号的文字
版本号可以使用表单的非标准字符串文字轻松表示 'v"。..". 版本号文字创建对象 'VersionNumber'https://semver.org /[语义版本控制],因此由主要版本号、次要版本号和补丁号的数值组成,然后是字母数字预发布和构建指定。 例如,`v"0.2.1-rc1+win64"'被拆分为主版本号'0、次版本号`2`、补丁版本号`1`、预发布值`rc1`和构建值’win64'。 当输入版本文字时,除了主版本号之外的所有内容都是可选的,因此,例如,
v"0.2"`等效于`v"0.2.0"
(具有空的预发布和构建名称),`v"2"`等效于`v"2.0.0"`等等。
'VersionNumber’对象主要用于两个(或更多)版本的简单和正确比较。 例如,常数 'VERSION'将Julia版本号存储为’VersionNumber’对象,因此您可以使用以下简单运算符定义一些特定于版本的行为。
if v"0.2" <= VERSION < v"0.3-"
# Выполнение чего-то конкретного для серии выпуска 0.2
end
请注意,上面的例子使用了一个非标准版本号`v'0.3-"`,结尾字符`-:这个符号是对标准的Julia扩展,用于指示一个低于任何版本号`0.3`的版本号,包括它的所有预 因此,在上面的例子中,代码将只与`0.2`的稳定版本一起工作,并排除`v"0.3.0-rc1"`等版本。 为了还允许'0.2’的不稳定(即预发布版本)版本,下界检查应更改如下’v"0.2-"<=VERSION
。
版本规范的另一个非标准扩展允许使用结束字符'`来表达程序集版本的上限。 例如,'VERSION>v"0.2-rc1"'可用于引用高于`0.2-rc1`的任何版本及其任何构建版本。:这将返回版本`v"0.2-rc1+win64"`的值`false`和`v"0.2-rc2"`的值`true`。
建议在比较中使用这种特殊版本(特别是,结束字符`-`应该总是在上界使用,除非有充分的理由不这样做),但它们不应该被用作某些东西的实际版本号,因为它们在语义版本控制方案中是不可接受的。
除了用于一个常数 VERSION
,`VersionNumber`对象在`Pkg’模块中广泛用于指定包版本及其依赖关系。
原始字符串文字
没有插值或转义的原始字符串可以使用格式为"raw"的非标准字符串文字来表示。..". 原始字符串字面量创建普通字符串对象,这些对象包含与输入内容完全相同的嵌套内容,而不进行插值或转义。 这非常适合包含其他语言中使用
$或
\`作为特殊字符的代码或标记的字符串。
例外情况是引号仍然必须转义。 例如,'raw"\""'相当于`"\""`。 要表达所有字符串,反斜杠也必须转义,但仅当它们立即出现在引号字符之前时。
julia> println(raw"\\ \\\"")
\\ \"
请注意,前两个反斜杠完全显示在输出中,因为它们不在引号字符前面。 但是,下一个反斜杠字符转义后面的反斜杠,最后一个反斜杠转义引号,因为这些反斜杠位于引号之前。
注释行
AnnotatedStrings的API被认为是实验性的,可以在Julia的不同版本中进行修改。 |
有时,能够存储与字符串区域相关的元数据是很有用的。 'AnnotatedString'包装另一个字符串,并允许您使用标记值(:label=>value
)注释其区域。 所有通用字符串操作都应用于基字符串。 然而,在可能的情况下,样式信息被保存。 这意味着你可以与 `AnnotatedString'--取子字符串,补充它们,将它们与其他字符串组合—并附加元数据注释。
这个字符串类型是主要的 StyledStrings stdlib,它使用标记为`:face`的注释,用于存储有关样式的信息。
串联时 'AnnotatedString'尝试使用 `annotatedstring'而不是 'string',如果要保存字符串注释。
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 * str2 == Base.annotatedstring(str, str2) # *-конкатенация все еще работает
true
访问注释 'AnnotatedString'和它们的修改是使用函数进行的 '注释'和 '注释!`.