现在位置: 首页 > Julia 教程 > 正文

Julia 字符串

字符串是由零个或多个字符组成的有限序列。它是编程语言中表示文本的数据类型。

Julia 通常使用单引号 ' 创建单个字符,双引号 " 或三个双引号 """ 创建字符串:

c = 'x'                                   # Char 字符

str = "RUNOOB"                            # String 字符串

runoob = """菜鸟教程 "RUNOOB",包含了引号"""   # 三引号字符串

Julia 字符串类型特性:

  • Julia 中用于字符串(和字符串字面量)的内置具体类型是 String。
  • Julia 的字符串类型都是抽象类型 AbstractString 的子类型。
  • Julia 有优秀的表示单字符的类型,即 AbstractChar。Char 是 AbstractChar 的内置子类型,它能表示任何 Unicode 字符的 32 位原始类型。
  • Julia 字符串是不可更改的——任何 AbstractString 对象的值不可改变,拼接等操作总是生成新的字符串。

字符

单个字符用 Char 值表示,字符字面量用单引号包围。

Char 是 32 位原始类型,可以转换为其对应的整数值,即 Unicode 码点:

实例

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

我们也可以将一个整数值转换回 Char:

实例

julia> Char(97)
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)

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

我们可以对 Char 的值进行比较和有限的算术运算:

实例

julia> 'A' < 'a'
true

julia> 'A' <= 'X' <= 'Z'
true

julia> 'x' - 'a'
23

julia> 'A' + 1
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)

字符串基础

Julia 中的字符串可以使用双引号 " 或三个双引号 """ 来声明。如果需要在字符串中使用双引号,就可以使用三个双引号来声明:

实例

julia> str = "RUNOOB"
"RUNOOB"

julia> runoob = """菜鸟教程 "RUNOOB",包含了双引号"""
"菜鸟教程 \"RUNOOB\",包含了双引号"

如果字符串太长了,我们可以使用反斜杠 \ 来换行书写:

实例

julia> "This is a long \
       line"

"This is a long line"

索引

Julia 字符串可以像数组一样使用索引来读取指定位置的字符,索引起始位置为 1 或者 begin,结束位置为 end

实例

julia> str = "RUNOOB"
"RUNOOB"

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

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

julia> str[2]
'U': ASCII/Unicode U+0055 (category Lu: Letter, uppercase)

julia> str[end]
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)

julia> str[end-1]
'O': ASCII/Unicode U+004F (category Lu: Letter, uppercase)

我们可以用范围索引来提取子字符串:

实例

julia> str[begin:end]
"RUNOOB"

julia> str[begin:end-1]
"RUNOO"

julia> str[2:5]
"UNOO"

另外,表达式 str[k]str[k:k] 给出的结果是不同的:前者通过索引获取指定位置的字符,类型是 Char;后者是通过给定的范围读取字符串,只是恰好包含一个字符的字符串:

实例

julia> str[6]
'B': ASCII/Unicode U+0042 (category Lu: Letter, uppercase)

julia> str[6:6]
"B"

范围截取也可以使用 SubString 方法来实现:

实例

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

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

julia> typeof(substr)
SubString{String}

多字节字符与字节索引

Julia 字符串使用 UTF-8 编码,一个中文字符占 3 个字节。字符串索引实际是字节索引,因此并非每个数字索引都有效:

UTF-8 字节索引布局示意图

实例

julia> s = "RUNOOB教程"

julia> s[1]
'R': ASCII/Unicode U+0052 (category Lu: Letter, uppercase)

# 第 7 个字节是"教"字的第一个字节,索引 5、6 落在字符中间,是无效索引
julia> s[7]
'教': Unicode U+6559 (category Lo: Letter, other)

julia> s[5]
ERROR: StringIndexError: invalid index [5], valid nearby indices [4]=>'B', [7]=>'教'
Stacktrace:
[...]

# length 计算字符数,ncodeunits 计算字节数
julia> length(s)
8

julia> ncodeunits(s)
12

# nextind / prevind 用于在有效索引间移动
julia> nextind(s, 1)
2

julia> collect(eachindex(s))    # 所有有效索引
8-element Vector{Int64}:
  1
  2
  3
  4
  5
  6
  7
 10

注意:遍历字符串时直接使用 for c in s 即可按字符迭代,不需要手动处理索引问题。


字符串拼接

拼接字符串有两种常用方式。第一种是 * 运算符,这是 Julia 的惯用写法:

实例

julia> greet = "Hello"
"Hello"

julia> whom = "world"
"world"

# * 号拼接字符串
julia> greet * ", " * whom * "!"
"Hello, world!"

Julia 用 * 而不是 + 拼接字符串,是因为字符串拼接不满足交换律("ab" 和 "ba" 不同),数学上非交换运算习惯用乘号表示。

第二种是 string() 函数,它可以拼接任意类型的值:

实例

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

^ 运算符可以重复字符串(等价于 repeat 函数):

实例

julia> "RUNOOB "^3
"RUNOOB RUNOOB RUNOOB "

julia> repeat("ab", 3)
"ababab"

插值

为了减少拼接的繁琐,Julia 允许像 Perl 中一样使用 $ 对字符串字面量进行插值:

实例

julia> "$greet, $whom!"
"Hello, world!"

在 $ 之后最短的完整表达式被视为插入其值于字符串中的表达式。因此,你可以用括号向字符串中插入任何表达式:

实例

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

# 对象会被转换为对应的字符串表示
julia> v = [1, 2, 3];

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

# Char 类型插入时不带引号
julia> c = 'x';

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> println(str)
  Hello,
  world.

如果开头的 """ 后紧跟换行,这个换行会被去掉,这让多行字符串在代码中的书写更加整洁:

实例

julia> """
         Hello,
         world."""

"Hello,\nworld."

Unicode 和 UTF-8

Julia 完全支持 Unicode 字符和字符串。

在字符字面量中,Unicode 码点可以用 \u(最多 4 位十六进制)和 \U(最多 8 位十六进制)转义序列表示:

实例

julia> s = "∀ x ∃ y"
"∀ x ∃ y"

字符串字面量用 UTF-8 编码。UTF-8 是一种可变长度的编码,ASCII 字符(码点小于 128 的)使用单字节编码,而码点 0x80 及以上的字符使用最多 4 个字节编码。


字符串比较与查找

我们可以使用比较操作符按照字典顺序比较字符串:

实例

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")    # 找不到时返回 nothing

你可以带上第三个参数,用 findnext 与 findprev 函数来在给定偏移量处搜索字符:

实例

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

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

你可以用 occursin 函数检查在字符串中某子字符串可否找到:

实例

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

julia> occursin("RUNOOB", "Hello, world.")
false

julia> occursin('o', "Xylophon")     # 也可以搜索单个字符
true

两个常用的转换函数 repeat 和 join:

实例

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

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

其他常用的字符串函数

函数描述
firstindex(str)可用来索引的最小索引(字符串总是 1)
lastindex(str)可用来索引的最大索引
length(str)str 中的字符个数
ncodeunits(str)字符串中代码单元(字节)的数目
codeunit(str, i)给出字符串 str 中索引为 i 的代码单元值
thisind(str, i)给定任意索引,查找所在字符的首个索引
nextind(str, i, n=1)查找索引 i 之后第 n 个字符的开头
prevind(str, i, n=1)查找索引 i 之前第 n 个字符的开始
startswith(s, prefix)判断 s 是否以 prefix 开头
endswith(s, suffix)判断 s 是否以 suffix 结尾
strip(s)去除两端空白字符
split(s, dlm)按分隔符拆分为子串数组
uppercase(s) / lowercase(s)转为大写 / 小写

实例

julia> startswith("runoob.com", "runoob")
true

julia> endswith("runoob.com", ".com")
true

julia> strip("  RUNOOB  ")
"RUNOOB"

julia> split("a,b,c", ",")
3-element Vector{SubString{String}}:
 "a"
 "b"
 "c"

julia> uppercase("runoob")
"RUNOOB"

原始字符串字面量

无插值和非转义的原始字符串可用 raw"..." 形式的非标准字符串字面量表示,内容与输入完全一样。这对包含正则表达式、LaTeX、Windows 路径等内容很有用:

实例

# 普通字符串会把 \n 解释成换行
julia> "runoob\nRUNOOB"
"runoob\nRUNOOB"

# raw 字符串保留原样
julia> raw"runoob\nRUNOOB"
"runoob\\nRUNOOB"

# raw 字符串中 $ 不插值
julia> x = 1;

julia> raw"x = $x"
"x = \$x"

例外的是,引号仍必须转义,例如 raw"\"" 等效于 "\""


字节数组与版本号字面量

Julia 还有两种常用的非标准字符串字面量:

b"..." 字节数组字面量,用于表示 UInt8 数组:

实例

julia> b"RUNOOB"
6-element Base.CodeUnits{UInt8, String}:
 0x52
 0x55
 0x4e
 0x4f
 0x4f
 0x42

v"..." 版本号字面量,创建 VersionNumber 对象,遵循语义化版本规范,常用于版本比较:

实例

julia> v"1.10.4"
v"1.10.4"

# 比较版本号
julia> v"1.10" < v"1.11"
true

# VERSION 是当前 Julia 的版本号
julia> VERSION >= v"1.6"
true