# textscan


从文本文件或字符串读取格式化数据。

函数库: TyBase

# 语法

C = textscan(fileID,formatSpec)
C = textscan(fileID,formatSpec,N)
C = textscan(chr,formatSpec)
C = textscan(chr,formatSpec,N)
C = textscan(___;Key=Value)
C,position = textscan(___)

# 说明

C = textscan(fileID,formatSpec) 将已打开的文本文件中的数据读取到数组 C。该文本文件由文件标识符 fileID 指示。使用 fopen 可打开文件并获取 fileID 值。完成文件读取后,请调用 fclose(fileID) 来关闭文件。

textscan 尝试将文件中的数据与 formatSpec 中的转换设定符匹配。textscan 函数在整个文件中按 formatSpec 重复扫描数据,直至 formatSpec 找不到匹配的数据时才停止。示例


C = textscan(fileID,formatSpec,N) 按 formatSpec 读取文件数据 N 次,其中 N 是一个正整数。要在 N 个周期后从文件读取其他数据,请使用原 fileID 再次调用 textscan 进行扫描。如果通过调用具有相同文件标识符 (fileID) 的 textscan 恢复文件的文本扫描,则 textscan 将在上次终止读取的点处自动恢复读取。示例


C = textscan(chr,formatSpec) 将字符 chr 中的文本读取到数组 C 中。从字符串读取文本时,对 textscan 的每一次重复调用都会从开头位置重新开始扫描。要从上次位置重新开始扫描,需要指定 position 输出参数。

textscan 尝试将字符 chr 中的数据与 formatSpec 中指定的格式匹配。示例


C = textscan(chr,formatSpec,N) 按 formatSpec N 次,其中 N 是一个正整数。


C = textscan(___;Key=Value) 使用一个或多个 Key,Value 关键词参数以及上述语法中的任何输入参数来指定选项。示例


C,position = textscan(___) 在扫描结束时返回文件或字符串中的位置作为第二个输出参数。对于文件,该值等同于调用 textscan 后再运行 ftell(fileID) 所返回的值。对于字符串,position 指示 textscan 读取了多少个字符。 示例

# 示例

读取浮点数

读取包含浮点数的字符串。

using TyBase
chr = "0.41 8.24 3.57 6.24 9.27"
C, pos = textscan(chr, "%f")

formatSpec 中的设定符 "%f" 指示 textscan 将 chr 中的每个字段与一个双精度浮点数进行匹配。

显示数组 C 的内容。

C[1]
5-element Vector{Float64}:
 0.41
 8.24
 3.57
 6.24
 9.27

读取相同字符串,将每个值截短至一位小数。

C, pos = textscan(chr, "%3.1f %*1d")

设定符 %3.1f 指示字段宽度为 3 位数,精度为 1。textscan 函数读取全部 3 位数,包括小数点和小数点后的 1 位数。设定符 %*1d 指示 textscan 跳过其余位数。

显示数组 C 的内容。

C[1]
5-element Vector{Float64}:
 0.4
 8.2
 3.5
 6.2
 9.2
读取十六进制数

读取一个表示一组十六进制数的字符串。表示十六进制数的文本包括数字 0-9,字母 a-f 或 A-F,以及可选的前缀 0x 或 0X。

要将 hexnums 中的字段与十六进制数匹配,请使用 "%x" 设定符。textscan 函数将字段转换为无符号 64 位整数。

using TyBase
hexnums = "0xFF 0x100 0x3C5E A F 10"
C, pos = textscan(hexnums, "%x")
(Vector{UInt64}[[0x00000000000000ff, 0x0000000000000100, 0x0000000000003c5e, 0x000000000000000a, 0x000000000000000f, 0x0000000000000010]], 24)

将 C 的内容显示为行向量。

C[1]
6-element Vector{UInt64}:
0x00000000000000ff
0x0000000000000100
0x0000000000003c5e
0x000000000000000a
0x000000000000000f
0x0000000000000010

您可以将字段转换为 8、16、32 或 64 位的有符号或无符号整数。要将 hexnums 中的字段转换为有符号 32 位整数,请使用 "%xs32" 设定符。

C, pos = textscan(hexnums, "%xs32")
C[1]
6-element Vector{Int32}:
255
256
15454
10
15
16

您还可以指定用来解释输入的字段宽度。在这种情况下,前缀将计入字段宽度。例如,如果您将字段宽度设置为三,如在 %3x 中所示,则 textscan 将文本 "0xAF 100" 拆分为三个文本片段,即 "0xA"、"F" 和 "100"。它将这三个文本片段视为不同的十六进制数。

C, pos = textscan("0xAF 100", "%3x")
C[1]
3-element Vector{UInt64}:
0x000000000000000a
0x000000000000000f
0x0000000000000100
读取二进制数

读取一个表示一组二进制数的字符串。表示二进制数的文本包括数字 0 和 1,以及可选的前缀 0b 或 0B。

要将 binnums 中的字段与二进制数匹配,请使用 "%b" 设定符。textscan 函数将字段转换为无符号 64 位整数。

using TyBase
binnums = "0b101010 0b11 0b100 1001 10"
C, pos = textscan(binnums, "%b")
(Vector{UInt64}[[0x000000000000002a, 0x0000000000000003, 0x0000000000000004, 0x0000000000000009, 0x0000000000000002]], 27)

将 C 的内容显示为行向量。

C[1]
5-element Vector{UInt64}:
0x000000000000002a
0x0000000000000003
0x0000000000000004
0x0000000000000009
0x0000000000000002

您可以将字段转换为 8、16、32 或 64 位的有符号或无符号整数。要将 binnums 中的字段转换为有符号 32 位整数,请使用 "%bs32" 设定符。

C, pos = textscan(binnums, "%bs32")
C[1]
5-element Vector{Int32}:
42
3
4
9
2

您还可以指定用来解释输入的字段宽度。在这种情况下,前缀将计入字段宽度。例如,如果您将字段宽度设置为三,如在 %3b 中所示,则 textscan 将文本 "0b1010 100" 拆分为三个文本片段,即 "0b1"、"010" 和 "100"。它将这三个文本片段视为不同的二进制数。

C, pos = textscan("0b1010 100", "%3b")
C[1]
3-element Vector{UInt64}:
0x0000000000000001
0x0000000000000002
0x0000000000000004
读取不同类型的数据

加载数据文件,并读取具有适当类型的每一列。

using TyBase
filename = pkgdir(TyBase) * "/examples/resources/textscan/scan1.txt"

打开文件,用正确的转换设定符读取每一列。textscan 返回一个 1-by-9 数组 C。

fileID = fopen(filename);
C, pos = textscan(fileID, "%s %s %f32 %d8 %f %f %f %s %s")
fclose(fileID)
C
9-element Vector{Vector}:
 ["09/12/2005", "10/12/2005", "11/12/2005"]
 ["Level1", "Level2", "Level3"]
 Float32[12.34, 23.54, 34.9]
 Int8[45, 60, 12]
 [1.23e10, 9.0e19, 200000.0]
 [Inf, -Inf, 10.0]
 [NaN, 0.001, 100.0]
 ["Yes", "No", "No"]
 ["5.1+3im", "2.2-.5im", "3.1+.1im"]

查看 C 中的每个元素的 Syslab 数据类型。

C[end] = parse.(Complex{Float64}, C[end])
C
9-element Vector{Vector}:
 ["09/12/2005", "10/12/2005", "11/12/2005"]
 ["Level1", "Level2", "Level3"]
 Float32[12.34, 23.54, 34.9]
 Int8[45, 60, 12]
 [1.23e10, 9.0e19, 200000.0]
 [Inf, -Inf, 10.0]
 [NaN, 0.001, 100.0]
 ["Yes", "No", "No"]
 ComplexF64[5.1 + 3.0im, 2.2 - 0.5im, 3.1 + 0.1im]
删除字面文本

从前一示例的第二列数据的每个字段中删除字面文本 "Level"。下面显示文件的预览。

using TyBase
filename = pkgdir(TyBase) * "/examples/resources/textscan/scan1.txt"

fileID = fopen(filename);
C, pos = textscan(fileID, "%s Level%d %f32 %d8 %f %f %f %s %s")
fclose(fileID)
C[end] = parse.(Complex{Float64}, C[end]) # 解析复数
C[2]
3-element Vector{Int64}:
 1
 2
 3
跳过每行的其余部分

将前一示例中文件的第一列读取到数组中,跳过行的其余部分。

using TyBase
filename = pkgdir(TyBase) * "/examples/resources/textscan/scan1.txt"

fileID = fopen(filename);
C, pos = textscan(fileID, "%s %*[^\n]")
fclose(fileID)
C[1]
3-element Vector{String}:
"09/12/2005"
"10/12/2005"
"11/12/2005"

textscan 返回一个日期数组。

指定分隔符和空值转换

读取该文件,将空转换为 -Inf。

using TyBase
filename = pkgdir(TyBase) * "/examples/resources/textscan/data.csv"

fileID = fopen(filename);
C, pos = textscan(fileID, "%f %f %f %f %u8 %f"; emptyvalue=-Inf, delimiter=",")
fclose(fileID)
C[4]
C[5]
2-element Vector{UInt8}:
0x00
0x0b

textscan 返回 1-by-6 数组 C。textscan 函数将 C[4] 中的空值转换为 -Inf,其中 C[4] 与浮点格式关联。因为 Syslab 将无符号整数 -Inf 表示为 0,所以 textscan 将 C[5] 中的空值转换为 0 而不是 -Inf。

指定要视为空或注释的文本

指定 textscan 应视为注释或空值的输入,并将该数据扫描到 C 中。

using TyBase
filename = pkgdir(TyBase) * "/examples/resources/textscan/data2.csv"

fileID = fopen(filename);
C, pos = textscan(
    fileID, "%s %f %f %f %f"; delimiter=",", treatasempty=["NA", "na"], commentstyle="//"
)
fclose(fileID)

显示输出。

C
5-element Vector{Vector}:
 ["abc", "def"]
 [2.0, NaN]
 [NaN, 5.0]
 [3.0, 6.0]
 [4.0, 7.0]
将重复的分隔符视为一个分隔符

要将重复的逗号视为单个分隔符,请使用 multipledelimsasone参数并将值设置为 true。

using TyBase
filename = pkgdir(TyBase) * "/examples/resources/textscan/data3.csv"

fileID = fopen(filename);
C, pos = textscan(fileID, "%f %f %f %f"; multipledelimsasone=true, delimiter=",")
fclose(fileID)
C
4-element Vector{Vector{Float64}}:
[1.0, 5.0]
[2.0, 6.0]
[3.0, 7.0]
[4.0, 8.0]
指定重复的转换设定符并收集数值数据

使用格式 "%s" 四次读取列标题。

using TyBase
filename = pkgdir(TyBase) * "/examples/resources/textscan/grades.txt"

fileID = fopen(filename);
C_text, pos = textscan(fileID, "%s", 4; delimiter="|")

读取文件中的数值数据。

C_data, pos = textscan(fileID, "%d %f %f %f")
C_data
4-element Vector{Vector}:
 [1, 2, 3, 4]
 [91.5, 88.0, 76.3, 96.4]
 [89.2, 67.8, 78.1, 81.2]
 [77.3, 91.0, 92.5, 84.6]

将文件位置指示符设置为文件的开头。

seek(fileID, 0)

重新读取文件。

C_text, pos = textscan(fileID, "%s", 4; delimiter="|");
C_data1, pos = textscan(fileID, "%d" * repeat("%f", 3))
C_data1 = [C_data1[1], cat(C_data1[2:end]...; dims=2)]
fclose(fileID)
C_data1
2-element Vector{Array}:
 [1, 2, 3, 4]
 [91.5 89.2 77.3; 88.0 67.8 91.0; 76.3 78.1 92.5; 96.4 81.2 84.6]
读取外语日期

加载文件并在文本编辑器中预览其内容。

using TyBase
filename = pkgdir(TyBase) * "/examples/resources/textscan/german_dates.txt"

fileID = fopen(filename);
C, pos = textscan(fileID, "%s %f %f"; delimiter = ",")
fclose(fileID)

查看 C 中第一个数组的内容。

C[1] = [DateTime(i, dateformat"dd U yyyy") for i in C[1]]
C[1]
3-element Vector{DateTime}:  
2014-01-01T00:00:00  
2014-02-01T00:00:00  
2014-03-01T00:00:00  
读取非默认的控制字符

使用 sprintf 转换数据中的非默认转义序列。

创建包含换页符 \f 的文本。随后,要使用 textscan 读取文本,请调用 sprintf 显式转换换页符。

using TyBase
lyric = "Blackbird\fsinging\fin\fthe\fdead\fof\fnight"
C, pos = textscan(lyric, "%s"; delimiter="\f")
C[1]
"Blackbird"  
"singing"  
"in"  
"the"  
"dead"  
"of"  
"night" 

textscan 返回数组 C。

恢复扫描

从开头以外的位置恢复扫描。

如果恢复文本扫描,textscan 每次都会从开头读取。要从任何其他位置恢复扫描,请在 textscan 的初始调用中使用双输出参数语法。

例如,创建一个名为 txt 的字符串。读取该字符串的第一个词,然后恢复扫描。

using TyBase
txt = "Blackbird singing in the dead of night"
firstword, pos = textscan(txt, "%9c", 1)
lastpart, _ = textscan(txt[pos+1:end], "%s")
([["singing", "in", "the", "dead", "of", "night"]], 28)

# 输入参数

fileID - 文件标识符
数值标量

已打开的文本文件的文件标识符,指定为数值。使用 textscan 读取文件之前,您必须使用 fopen 打开文件并获取 fileID。

数据类型: IOStream

formatSpec - 数据字段的格式
字符串

数据字段的格式,指定为由一个或多个转换设定符组成的字符串。textscan 在读取输入时,会尝试将数据与 formatSpec 中指定的格式进行匹配。如果 textscan 未能匹配数据字段,它将会停止读取并在出错前返回读取的所有字段。

转换设定符的数量确定输出数组 C 中的数量。

数值字段

下表列出了可用于数值输入的转换设定符。

数值输入类型 转换设定符 输出类
有符号整数 %d Int32
有符号整数 %d8 Int8
有符号整数 %d16 Int16
有符号整数 %d32 Int32
有符号整数 %d64 Int64
无符号整数 %u UInt32
无符号整数 %u8 UInt8
无符号整数 %u16 UInt16
无符号整数 %u32 UInt32
无符号整数 %u64 UInt64
浮点数 %f float64
浮点数 %f32 float32
浮点数 %f64 float64
浮点数 %n float64
十六进制数、无符号整数 %x UInt64
十六进制数、无符号整数 %xu8 UInt8
十六进制数、无符号整数 %xu16 UInt16
十六进制数、无符号整数 %xu32 UInt32
十六进制数、无符号整数 %xu64 UInt64
十六进制数、有符号整数 %xs8 In8
十六进制数、有符号整数 %xs16 Int16
十六进制数、有符号整数 %xs32 Int32
十六进制数、有符号整数 %xs64 Int64
二进制数、无符号整数 %b UInt64
二进制数、无符号整数 %bu8 UInt8
二进制数、无符号整数 %bu16 UInt16
二进制数、无符号整数 %bu32 UInt32
二进制数、无符号整数 %bu64 UInt64
二进制数、有符号整数 %bs8 Int8
二进制数、有符号整数 %bs16 Int16
二进制数、有符号整数 %bs32 Int32
二进制数、有符号整数 %bs64 Int64

非数值字段

下表列出了可用于包含非数值字符的输入的转换设定符。

非数值输入类型 转换设定符 详细信息
字符 %c 读取任何单个字符,包括分隔符。
文本数组 %s 读取为字符串数组。
模式匹配 %[...] 将方括号中的字符读取为字符串数组,直到遇到第一个不匹配的字符。要在集合中包括 ],请首先指定它:%[]...]。示例:%[mus] 将 'summer ' 读作 'summ'。
模式匹配 %[...] 排除方括号中的字符,直到读取到第一个匹配的字符。要排除 ],请首先指定它:%[^]...]。示例:%[^xrg] 将 'summer ' 读作 'summe'。

可选运算符

formatSpec 中的转换设定符可以包含按以下顺序显示的可选运算符(包含为了表达清晰而保留的空格):

可选运算符包括:

要忽略的字段和字符

textscan 按顺序读取文件中的所有字符,除非您要求它忽略特定字段或字段中的某一部分。

在百分比字符 (%) 之后插入星号字符 (*),可跳过某个字段或字符字段中的某一部分。

运算符 采取的操作
%* k 跳过字段。k 是标识要跳过的字段的任何转换设定符。textscan 不会为任何此类字段创建输出。示例:'%s %*s %s %s %*s %*s %s'(空格为可选项)将文本'Blackbird singing in the dead of night' 转换为四个输出,即'Blackbird' 'in' 'the' 'night'
'%* ns' 跳过 n 个字符,其中 n 是小于或等于字段中字符数的一个整数。示例:'%*3s %s' 将 'abcdefg' 转换为 'defg'。如果分隔符为逗号,则同一分隔符将 'abcde,fghijkl' 转换为包含 'de';'ijkl' 的数组。
'%*nc' 跳过 n 个字符,包括分隔符。

字段宽度

textscan 读取字段宽度或精度指定的字符数或位数,或者读到第一个分隔符,以先出现者为准。小数点、符号(+ 或 -)、指数字符以及数字指数中的数字计为字段宽度中的字符和数字。对于复数,字段宽度指的是实部和虚部的各自宽度。对于虚部,字段宽度包括 + 或 −,但不包括 i 或 j。通过在转换设定符中的百分号 (%) 之后插入数字来指定字段宽度。

示例:%5f 将 "123.456" 读作 123.4。

示例:%5c 将 'abcdefg' 读作 'abcde'。

当字段宽度操作符与单个字符 (%c) 一起使用时,textscan 也会读取分隔符、空白和行尾字符。 示例:%7c 读取包括空白在内的 7 个字符,因此 "Day and night" 读作 "Day and"。

精度

对于浮点数(%n、%f、%f32、%f64),可以指定要读取的小数位数。

示例:%7.2f 将 "123.456" 读作 123.45。

要忽略的字面文本

textscan 忽略追加到 formatSpec 转换设定符的文本。

示例:Level%u8 将 "Level1" 读作 1。

示例:%u8Step 将 "2Step" 读作 2。

数据类型: String

N - 要应用formatSpec的次数
uint8=>Inf (默认) | 正整数

要应用 formatSpec 的次数,指定为正整数。

数据类型: float32 | float64 | Int8 | Int16 | Int32 | Int64 | UInt8 | UInt16 | UInt32 | UInt64

chr - 输入文本
字符串

要读取的输入文本。

数据类型: String

# 名称-值对组参数

指定可选的关键词参数。在分号后,以逗号分隔的 Key = Value 对组参数。Key 为关键词参数名称,Value 为对应的值。您可采用任意顺序指定多个名称-值对组参数,如 Key1 = Value1,...,KeyN = ValueN 所示。

示例: C = textscan(fileID,formatSpec;headerlines=3,delimiter=",") 跳过数据的前三行,然后读取其余数据,并将逗号视为分隔符。

名称不区分大小写。

commentstyle - 指定要忽略的文本的符号
字符串

用于指定要忽略的文本的符号,指定为逗号分隔的对组,其中包含 commentstyle 字符串。

例如,指定一个字符串(如 "//")。

SYSLAB 仅检查位于每个字段开头而不是字段中的注释。

示例: commentstyle = "//"

数据类型: String

delimiter - 字段分隔符
字符串 | 字符串数组

示例: delimiter="*./"

textscan 将重复的分隔符字符解释为多个分隔符,并向输出返回一个空值。

在每一行数据中,默认字段分隔符是空白。空白可以是空格 (" ")、退格符 ("\b") 或制表符 ("\t") 的任意组合。如果您未指定分隔符,则:

分隔符与空白字符相同。默认的空白字符为 " "、"\b" 和 "\t"。

textscan 将重复的空白字符解释为单个分隔符。

数据类型: String

emptyvalue - 空数值字段的返回值
NaN (默认) | 标量

被分隔的文本文件中空数值字段的返回值,指定为由 emptyvalue 和一个标量组成的逗号分隔对组。

headerlines - 标题行数
0 (默认) | 正整数

标题行数,指定为由 headerlines 和一个正整数组成的逗号分隔对组。textscan 会跳过标题行,包括当前行的剩余部分。

数据类型: Integer

multipledelimsasone - 多分隔符处理
false(默认) | true

多分隔符处理,指定为由 multipledelimsasone 和 true/false 组成的逗号分隔对组。如果为 true,则导入函数将连续分隔符当作一个分隔符处理。由空白分隔的重复分隔符也被当作一个分隔符处理。您还必须指定 Delimiter 选项。

示例: multipledelimsasone=true

数据类型: Bool

treatasempty - 要作为空值处理的占位符文本
字符串

要作为空值处理的占位符文本,指定为逗号分隔的对组,其中包含 treatasempty 和一个字符串或。此选项仅适用于数值字段。

数据类型: String

# 输出参数

C - 文件或文本数据
数组

文件或文本数据,以数组形式返回。

对于 formatSpec 中的每个数值转换设定符,textscan 函数将一个 K×1 Syslab 数值向量返回给输出数组 C,其中 K 是 textscan 查找与此设定符匹配的字段的次数。

对于 formatSpec 中的每个文本转换设定符(%s、或 %[...]),textscan 函数都返回一个 K×1 字符串数组,其中 K 是 textscan 查找与此设定符匹配的字段的次数。对于包含字段宽度操作符的每个字符转换,textscan 返回一个 K×M 字符数组,其中 M 是字段宽度。

对于 formatSpec 中的每个日期时间或分类转换设定符,textscan 函数将一个 K×1 日期时间或分类向量返回给输出数组 C,其中 K 是 textscan 查找与此设定符匹配的字段的次数。

position - 文件或字符串中的位置
整数

扫描结束时在文件或字符串中的位置,以整数形式返回。对于文件,该值等同于调用 textscan 后运行 ftell(fileID) 所返回的值。对于字符串,position 指示 textscan 读取了多少个字符。

数据类型: Integer

# 另请参阅

fopen | fread | fscanf | load