2 Star 13 Fork 3

advanceflow/Elisp

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
04-字符串和字符.org 55.04 KB
一键复制 编辑 原始数据 按行查看 历史
advanceflow 提交于 2022-05-28 10:12 . finish s2

4 字符串和字符

Emacs Lisp 中的字符串是一个包含有序字符序列的数组。 字符串用作符号、缓冲区和文件的名称; 向用户发送消息; 保存在缓冲区之间复制的文本; 并用于许多其他目的。 因为字符串非常重要,Emacs Lisp 有许多专门用于操作它们的函数。 Emacs Lisp 程序比单个字符更频繁地使用字符串。

有关键盘字符事件字符串的特殊注意事项,请参阅将键盘事件放入字符串中。

4.1 字符串和字符基础

字符是一个 Lisp 对象,它表示文本的单个字符。 在 Emacs Lisp 中,字符只是整数; 整数是否为字符仅取决于它的使用方式。 有关 Emacs 中字符表示的详细信息,请参阅字符代码。

字符串是固定的字符序列。 它是一种称为数组的序列,这意味着它的长度是固定的,一旦创建就不能更改(请参阅序列、数组和向量)。 与 C 不同,Emacs Lisp 字符串不以可区分的字符代码终止。

由于字符串是数组,因此也是序列,您可以使用序列、数组和向量中记录的通用数组和序列函数对它们进行操作。 例如,您可以使用函数 aref 访问字符串中的单个字符(请参阅对数组进行操作的函数)。

Emacs 字符串(和缓冲区)中的非 ASCII 字符有两种文本表示:单字节和多字节。 对于大多数 Lisp 编程,您不需要关心这两种表示。 有关详细信息,请参阅文本表示。

有时键序列表示为单字节字符串。 当单字节字符串是键序列时,128 到 255 范围内的字符串元素表示元字符(它们是大整数)而不是 128 到 255 范围内的字符代码。字符串不能包含具有 hyper、super 或 alt 修饰符的字符; 它们可以保存 ASCII 控制字符,但不能保存其他控制字符。 它们不区分 ASCII 控制字符的大小写。 如果要将此类字符存储在序列中,例如键序列,则必须使用向量而不是字符串。 有关键盘输入字符的更多信息,请参阅字符类型。

字符串对于保存正则表达式很有用。 您还可以使用 string-match 将正则表达式与字符串进行匹配(请参阅正则表达式搜索)。 函数 match-string(请参阅简单匹配数据访问)和 replace-match(请参阅替换匹配的文本)对于在匹配正则表达式后分解和修改字符串很有用。

像缓冲区一样,字符串可以包含其中字符的文本属性,以及字符本身。 请参阅文本属性。 所有将文本从字符串复制到缓冲区或其他字符串的 Lisp 原语也复制被复制字符的属性。

有关显示字符串或将字符串复制到缓冲区的函数的信息,请参阅文本。 有关字符和字符串的语法的信息,请参阅字符类型和字符串类型。 有关在文本表示之间进行转换以及对字符代码进行编码和解码的函数,请参见非 ASCII 字符。 另外,请注意,长度不应用于计算显示字符串的宽度; 请改用字符串宽度(请参阅显示文本的大小)。

4.2 字符串谓词

有关一般序列和数组谓词的更多信息,请参阅序列、数组和向量以及数组。

Function: stringp object

如果 object 是字符串,此函数返回 t,否则返回 nil。

Function: string-or-null-p object

如果 object 是字符串或 nil,则此函数返回 t。 否则返回 nil 。

Function: char-or-string-p object

如果 object 是字符串或字符(即整数),则此函数返回 t,否则返回 nil。

4.3 创建字符串

以下函数创建字符串,可以从头开始,也可以将字符串放在一起,或者将它们分开。 (对于根据其他字符串的修改内容创建字符串的函数,如 string-replace 和 replace-regexp-in-string,请参阅搜索和替换。)

Function: make-string count character &optional multibyte

此函数返回一个由 count 重复字符组成的字符串。 如果计数为负,则发出错误信号。

  (make-string 5 ?x)
	   ⇒ "xxxxx"
  (make-string 0 ?x)
	   ⇒ ""

通常,如果字符是 ASCII 字符,则结果是单字节字符串。 但是,如果可选参数 multibyte 不为 nil,则该函数将生成一个多字节字符串。 当您稍后需要将结果与非 ASCII 字符串连接或用非 ASCII 字符替换其中的一些字符时,这很有用。

与此比较的其他函数包括 make-vector(请参阅 Vectors)和 make-list(请参阅 Building Cons Cells and Lists)。

Function: string &rest characters

这将返回一个包含字符的字符串。

(string ?a ?b ?c)
     ⇒ "abc"
Function: substring string &optional start end

此函数返回一个新字符串,该字符串由字符串中的那些字符组成,范围从(并包括)索引开始处的字符到(但不包括)索引结束处的字符。 第一个字符位于索引零处。 有一个参数,这个函数只是复制字符串。

(substring "abcdefg" 0 3)
     ⇒ "abc"

在上面的例子中,’a’ 的索引是 0,’b’ 的索引是 1,’c’ 的索引是 2。索引 3(字符串中的第四个字符)标记了字符位置子字符串被复制到的位置。 因此,“abc”是从字符串“abcdefg”复制而来的。

负数从字符串末尾开始计数,因此 -1 表示字符串最后一个字符的索引。 例如:

(substring "abcdefg" -3 -1)
     ⇒ "ef"

在此示例中,“e”的索引为 -3,“f”的索引为 -2,“g”的索引为 -1。 因此,“e”和“f”被包括在内,“g”被排除在外。

当 nil 用于 end 时,它代表字符串的长度。 因此,

(substring "abcdefg" -3 nil)
     ⇒ "efg"

省略参数 end 等效于指定 nil。 随之而来的是 (substring string 0) 返回所有字符串的副本。

(substring "abcdefg" 0)
     ⇒ "abcdefg"

但我们建议为此目的使用复制序列(请参阅序列)。

如果从字符串复制的字符具有文本属性,则这些属性也会复制到新字符串中。 请参阅文本属性。

substring 还接受第一个参数的向量。 例如:

(substring [a b (c) "d"] 1 3)
     ⇒ [b (c)]

如果 start 不是整数或 end 既不是整数也不是 nil,则会发出错误类型参数错误的信号。 如果 start 指示字符跟在 end 之后,或者任何一个整数超出字符串的范围,则会发出 args-out-of-range 错误信号。

将此函数与 buffer-substring 进行对比(请参阅检查缓冲区内容),后者返回一个字符串,其中包含当前缓冲区中的部分文本。 字符串的开头是索引 0,但缓冲区的开头是索引 1。

Function: substring-no-properties string &optional start end

这类似于子字符串,但会丢弃值中的所有文本属性。 此外, start 可以省略或 nil,相当于 0。因此,(substring-no-properties string) 返回字符串的副本,删除所有文本属性。

Function: concat &rest sequences

此函数返回一个字符串,该字符串由传递给它的参数中的字符组成(以及它们的文本属性,如果有的话)。 参数可以是字符串、数字列表或数字向量; 他们自己并没有改变。 如果 concat 没有接收到参数,它会返回一个空字符串。

(concat "abc" "-def")
     ⇒ "abc-def"
(concat "abc" (list 120 121) [122])
     ⇒ "abcxyz"
;; nil is an empty sequence.
(concat "abc" nil "-def")
     ⇒ "abc-def"
(concat "The " "quick brown " "fox.")
     ⇒ "The quick brown fox."
(concat)
     ⇒ ""

这个函数并不总是分配一个新的字符串。 建议调用者不要依赖结果是一个新字符串,也不要依赖它是现有字符串的 eq。

特别是,改变返回值可能会无意中更改另一个字符串,更改程序中的常量字符串,甚至引发错误。 要获得可以安全地变异的字符串,请对结果使用复制序列。

有关其他连接函数的信息,请参见 Mapping Functions 中的 mapconcat 的描述,Vectors 中的 vconcat 以及 Building Cons Cells and Lists 中的 append。 要将单个命令行参数连接成一个字符串以用作 shell 命令,请参阅 combine-and-quote-strings。

Function: split-string string &optional separators omit-nulls trim

此函数根据正则表达式分隔符将字符串拆分为子字符串(请参阅正则表达式)。 分隔符的每个匹配定义一个拆分点; 将分割点之间的子串做成一个列表,并返回。

如果 separators 为 nil(或省略),则默认值为 split-string-default-separators 的值,并且该函数的行为就像 omit-nulls 为 t。

如果 omit-nulls 为 nil(或省略),则只要有两个连续的分隔符匹配,或者匹配与字符串的开头或结尾相邻,结果就会包含空字符串。 如果 omit-nulls 为 t,则从结果中省略这些空字符串。

如果可选参数 trim 不是 nil,它应该是一个正则表达式来匹配要从每个子字符串的开头和结尾修剪的文本。 如果修剪使子字符串为空,则将其视为 null。

如果您需要将字符串拆分为适合调用进程或启动进程的单个命令行参数列表,请参阅 split-string-and-unquote。

例子:

(split-string "  two words ")
     ⇒ ("two" "words")

结果不是 (“” “two” “words” “”),它很少有用。 如果您需要这样的结果,请为分隔符使用显式值:

(split-string "  two words "
              split-string-default-separators)
     ⇒ ("" "two" "words" "")
(split-string "Soup is good food" "o")
     ⇒ ("S" "up is g" "" "d f" "" "d")
(split-string "Soup is good food" "o" t)
     ⇒ ("S" "up is g" "d f" "d")
(split-string "Soup is good food" "o+")
     ⇒ ("S" "up is g" "d f" "d")

空匹配确实计数,除了当 split-string 已经使用非空匹配到达字符串末尾或字符串为空时,它不会寻找最终的空匹配:

  (split-string "aooob" "o*")
	   ⇒ ("" "a" "" "b" "")
  (split-string "ooaboo" "o*")
	   ⇒ ("" "" "a" "b" "")
  (split-string "" "")
	   ⇒ ("")

但是,当分隔符可以匹配空字符串时,省略空值通常为 t,因此前面三个示例中的微妙之处很少相关:

  (split-string "Soup is good food" "o*" t)
	   ⇒ ("S" "u" "p" " " "i" "s" " " "g" "d" " " "f" "d")
  (split-string "Nice doggy!" "" t)
	   ⇒ ("N" "i" "c" "e" " " "d" "o" "g" "g" "y" "!")
  (split-string "" "" t)
	   ⇒ nil

对于某些“非贪婪”分隔符值,可能会出现一些奇怪但可预测的行为,这些分隔符可能更喜欢空匹配而不是非空匹配。 同样,这样的值在实践中很少出现:

  (split-string "ooo" "o*" t)
	   ⇒ nil
  (split-string "ooo" "\\|o+" t)
	   ⇒ ("o" "o" "o")
Variable: split-string-default-separators

split-string 的分隔符的默认值。 它的通常值为“[ \f\t\n\r\v]+”。

Function: string-clean-whitespace string

通过将一段空格折叠为单个空格字符,以及从字符串的开头和结尾删除所有空格来清理字符串中的空格。

Function: string-trim-left string &optional regexp

从字符串中删除与正则表达式匹配的前导文本。 正则表达式默认为 ‘[ \t\n\r]+’。

Function: string-trim-right string &optional regexp

从字符串中删除匹配正则表达式的尾随文本。 正则表达式默认为 ‘[ \t\n\r]+’。

Function: string-trim string &optional trim-left trim-right

从字符串中删除匹配 trim-left 的前导文本和匹配 trim-right 的尾随文本。 两个正则表达式都默认为 ‘[ \t\n\r]+’。

Function: string-fill string length

尝试对字符串进行自动换行,以便没有行长于长度。 填充仅在空白边界上完成。 如果有个别词长于长度,这些将不会被缩短。

Function: string-limit string length &optional end coding-system

如果 string 比 length 个字符短,则按原样返回 string。 否则,返回由第一个长度字符组成的字符串子串。 如果给出了可选的 end 参数,则返回一个长度为最后一个字符的字符串。

如果coding-system 不为零,则在限制之前对字符串进行编码,结果将是一个比长度字节短的单字节字符串。 如果字符串包含被编码为多个字节的字符(例如,使用 utf-8 时),则生成的单字节字符串永远不会在字符表示的中间被截断。

此函数以字符或字节为单位测量字符串长度,因此如果您需要缩短字符串以进行显示,通常不适合; 请改用 truncate-string-to-width 或 window-text-pixel-size(请参阅显示文本的大小)。

Function: string-lines string &optional omit-nulls

将字符串拆分为换行符边界上的字符串列表。 如果省略空值,则从结果中删除空行。

Function: string-pad string length &optional padding start

使用 padding 作为填充字符(默认为空格字符)将字符串填充到长度。 如果字符串短于长度,则不进行填充。 如果 start 为 nil(或不存在),则填充到字符串的末尾,如果它不是 nil,则填充到字符串的开头。

Function: string-chop-newline string

从字符串中删除最后的换行符(如果有)。

4.4 修改字符串

您可以通过本节中描述的操作更改可变字符串的内容。 请参阅可变性。

更改现有字符串内容的最基本方法是使用 aset(请参阅操作数组的函数)。 (aset string idx char) 将 char 存储到索引 idx 处的字符串中。 每个字符占用一个或多个字节,如果 char 需要与该索引处已经存在的字符不同的字节数,则 aset 会发出错误信号。

一个更强大的功能是 store-substring:

Function: store-substring string idx obj

此函数通过存储从索引 idx 开始的 obj 来更改字符串 string 的部分内容。 参数 obj 可以是一个字符或一个(较小的)字符串。

由于不可能更改现有字符串的长度,因此如果 obj 不适合字符串的实际长度,或者任何新字符需要与字符串中该点当前存在的字符不同的字节数,则会出现错误。

要清除包含密码的字符串,请使用 clear-string:

Function: clear-string string

这使 string 成为单字节字符串并将其内容清除为零。 它也可能改变字符串的长度。

4.5 字符与字符串的比较

Function: char-equal character1 character2

如果参数表示相同的字符,此函数返回 t,否则返回 nil。 如果 case-fold-search 不为零,此函数将忽略大小写的差异。

     (char-equal ?x ?x)
	   ⇒ t
     (let ((case-fold-search nil))
	(char-equal ?x ?X))
	   ⇒ nil
Function: string= string1 string2

如果两个字符串的字符完全匹配,则此函数返回 t。 符号也可以作为参数,在这种情况下使用符号名称。 无论大小写搜索如何,大小写总是很重要的。

此函数等效于比较两个字符串的 equal(请参阅 Equality Predicates)。 特别是忽略了两个字符串的文本属性; 如果您需要区分仅在文本属性上有所不同的字符串,请使用 equal-include-properties。 但是,与 equal 不同的是,如果任一参数不是字符串或符号,则 string= 表示错误。

  (string= "abc" "abc")
	   ⇒ t
  (string= "abc" "ABC")
	   ⇒ nil
  (string= "ab" "ABC")
	   ⇒ nil

出于技术原因,当且仅当单字节和多字节字符串包含相同的字符代码序列并且所有这些代码都在 0 到 127(ASCII)或 160 到 255(八位图形)范围内时,它们才相等. 但是,当单字节字符串转换为多字节字符串时,代码在 160 到 255 范围内的所有字符都将转换为代码更高的字符,而 ASCII 字符保持不变。 因此,单字节字符串及其到多字节的转换只有在字符串都是 ASCII 时才相等。 字符代码 160 到 255 在多字节文本中并不完全正确,即使它们可能出现。 因此,一个单字节字符串和一个多字节字符串是相等的而不都是 ASCII 的情况是一个技术上的怪事,很少有 Emacs Lisp 程序员遇到过。 请参阅文本表示。

Function: string-equal string1 string2

string-equal 是 string= 的另一个名称。

Function: string-collate-equalp string1 string2 &optional locale ignore-case

如果 string1 和 string2 在排序规则方面相等,则此函数返回 t。 排序规则不仅取决于 string1 和 string2 中包含的字符的字典顺序,还取决于这些字符之间的关系的进一步规则。 通常,它是由运行 Emacs 的语言环境定义的。

例如,具有不同编码点但含义相同的字符可能被视为相等,例如不同的重音 Unicode 字符:

  (string-collate-equalp (string ?\uFF40) (string ?\u1FEF))
	   ⇒ t

可选参数 locale 是一个字符串,它会覆盖当前区域设置标识符的设置以进行排序。 该值取决于系统; 区域设置“en_US.UTF-8”适用于 POSIX 系统,而例如“enu_USA.1252”适用于 MS-Windows 系统。

如果 ignore-case 不为零,则字符在比较之前会转换为小写。

要在 MS-Windows 系统上模拟符合 Unicode 的排序规则,请将 w32-collat​​e-ignore-punctuation 绑定到非零值,因为在 MS-Windows 上区域设置的代码集部分不能是“UTF-8”。

如果您的系统不支持 locale 环境,则此函数的行为类似于 string-equal。

不要使用此函数来比较文件名是否相等,因为文件系统通常不尊重排序规则实现的字符串的语言等价性。

Function: string< string1 string2

此函数一次比较两个字符串一个字符。 它同时扫描两个字符串以找到第一对不匹配的对应字符。 如果这两个中较小的字符是来自 string1 的字符,则 string1 较小,并且此函数返回 t。 如果较小的字符是来自 string2 的字符,则 string1 较大,并且此函数返回 nil。 如果两个字符串完全匹配,则值为 nil。

成对的字符根据它们的字符代码进行比较。 请记住,小写字母在 ASCII 字符集中的数值高于其对应的大写字母; 数字和许多标点字符的数值低于大写字母。 一个 ASCII 字符小于任何非 ASCII 字符; 单字节非 ASCII 字符总是小于任何多字节非 ASCII 字符(参见文本表示)。

  (string< "abc" "abd")
	   ⇒ t
  (string< "abd" "abc")
	   ⇒ nil
  (string< "123" "abc")
	   ⇒ t

当字符串具有不同的长度,并且它们匹配到 string1 的长度时,则结果为 t。 如果它们匹配到 string2 的长度,则结果为零。 没有字符的字符串小于任何其他字符串。

  (string< "" "abc")
	   ⇒ t
  (string< "ab" "abc")
	   ⇒ t
  (string< "abc" "")
	   ⇒ nil
  (string< "abc" "ab")
	   ⇒ nil
  (string< "" "")
	   ⇒ nil

符号也可以作为参数,在这种情况下,它们的打印名称会被比较。

Function: string-lessp string1 string2

string-lessp 是 string< 的另一个名称。

Function: string-greaterp string1 string2

该函数以相反的顺序返回string1和string2的比较结果,即相当于调用(string-lessp string2 string1)。

Function: string-collate-lessp string1 string2 &optional locale ignore-case

如果 string1 按排序顺序小于 string2,则此函数返回 t。 排序顺序不仅取决于 string1 和 string2 中包含的字符的字典顺序,还取决于这些字符之间的关系的进一步规则。 通常,它是由运行 Emacs 的语言环境定义的。

例如,排序时可能会忽略标点符号和空格字符(请参阅序列):

  (sort (list "11" "12" "1 1" "1 2" "1.1" "1.2") 'string-collate-lessp)
	   ⇒ ("11" "1 1" "1.1" "12" "1 2" "1.2")

此行为取决于系统; 例如,无论语言环境如何,Cygwin 上都不会忽略标点符号和空格。

可选参数 locale 是一个字符串,它会覆盖当前区域设置标识符的设置以进行排序。 该值取决于系统; 区域设置“en_US.UTF-8”适用于 POSIX 系统,而例如“enu_USA.1252”适用于 MS-Windows 系统。 “POSIX”或“C”的语言环境值让 string-collat​​e-lessp 表现得像 string-lessp:

  (sort (list "11" "12" "1 1" "1 2" "1.1" "1.2")
	    (lambda (s1 s2) (string-collate-lessp s1 s2 "POSIX")))
	   ⇒ ("1 1" "1 2" "1.1" "1.2" "11" "12")

如果 ignore-case 不为零,则字符在比较之前会转换为小写。

要在 MS-Windows 系统上模拟符合 Unicode 的排序规则,请将 w32-collat​​e-ignore-punctuation 绑定到非零值,因为在 MS-Windows 上区域设置的代码集部分不能是“UTF-8”。

如果您的系统不支持 locale 环境,则此函数的行为类似于 string-lessp。

Function: string-version-lessp string1 string2

此函数按字典顺序比较字符串,但它将数字字符序列视为包含以十为基数的数字,然后比较这些数字。 所以根据这个谓词,’foo2.png’ 比 ‘foo12.png’ “小”,即使 ‘12’ 在字典上比 ‘2’ “小”。

Function: string-prefix-p string1 string2 &optional ignore-case

如果 string1 是 string2 的前缀,则此函数返回非 nil; 即,如果string2 以string1 开头。 如果可选参数 ignore-case 不为零,则比较忽略大小写差异。

Function: string-suffix-p suffix string &optional ignore-case

如果 suffix 是字符串的后缀,此函数返回非 nil; 即,如果字符串以后缀结尾。 如果可选参数 ignore-case 不为零,则比较忽略大小写差异。

Function: string-search needle haystack &optional start-pos 

返回 haystack 中第一个 needle 实例的位置,两者都是字符串。 如果 start-pos 不为零,则从针中的该位置开始搜索。 如果未找到匹配项,则返回 nil。 该函数在进行比较时只考虑字符串中的字符; 文本属性被忽略。 匹配始终区分大小写。

Function: compare-strings string1 start1 end1 string2 start2 end2 &optional ignore-case 

此函数将 string1 的指定部分与 string2 的指定部分进行比较。 string1 的指定部分从索引 start1(包括)一直到索引 end1(不包括); start1 的 nil 表示字符串的开头,而 end1 的 nil 表示字符串的长度。 同样,string2 的指定部分从索引 start2 一直运行到索引 end2。

字符串通过其字符的数值进行比较。 例如,如果 str1 的第一个不同字符具有较小的数值,则认为 str1 小于 str2。 如果 ignore-case 不为零,则字符在比较之前转换为大写。 单字节字符串被​​转换为多字节以进行比较(请参阅文本表示),因此单字节字符串及其到多字节的转换始终被视为相等。

如果两个字符串的指定部分匹配,则值为 t。 否则,该值是一个整数,表示有多少前导字符一致,哪个字符串少。 它的绝对值是一加两个字符串开头一致的字符数。 如果 string1(或其指定部分)小于,则符号为负。

Function: string-distance string1 string2 &optional bytecompare 

此函数返回源字符串 string1 和目标字符串 string2 之间的 Levenshtein 距离。 Levenshtein 距离是将源字符串转换为目标字符串所需的单个字符更改(删除、插入或替换)的数量; 这是字符串之间编辑距离的一种可能定义。

字符串的字母大小写对于计算距离很重要,但它们的文本属性被忽略。 如果可选参数 bytecompare 不为 nil,则函数以字节而不是字符来计算距离。 逐字节比较使用字符的内部 Emacs 表示,因此对于包含原始字节的多字节字符串会产生不准确的结果(请参阅文本表示); 如果您需要原始字节的准确结果,请通过对字符串进行编码(请参阅显式编码和解码)使字符串成为单字节。

Function: assoc-string key alist &optional case-fold 

这个函数和 assoc 一样工作,除了 key 必须是一个字符串或符号,并且比较是使用 compare-strings 完成的。 符号在测试前被转换为字符串。 如果 case-fold 不为 nil,则 key 和 alist 的元素在比较之前转换为大写。 与 assoc 不同,此函数还可以匹配 alist 中的字符串或符号元素,而不是 conses。 特别是,alist 可以是字符串或符号的列表,而不是实际的 alist。 请参阅关联列表。

另请参阅比较文本中的函数 compare-buffer-substrings,了解比较缓冲区中文本的方法。 函数 string-match 将正则表达式与字符串进行匹配,可用于一种字符串比较; 请参阅正则表达式搜索。

4.6 字符和字符串的转换

本节介绍用于在字符、字符串和整数之间进行转换的函数。 format(请参阅格式化字符串)和 prin1-to-string(请参阅输出函数)也可以将 Lisp 对象转换为字符串。 read-from-string(参见输入函数)可以将 Lisp 对象的字符串表示形式转换为对象。 函数 string-to-multibyte 和 string-to-unibyte 转换字符串的文本表示(请参阅转换文本表示)。

有关生成文本字符的文本描述和一般输入事件(单键描述和文本字符描述)的函数,请参阅文档。 这些主要用于制作帮助信息。

Function: number-to-string number 

此函数返回一个字符串,该字符串由打印的以十为基数的数字表示形式组成。 如果参数为负,则返回值以减号开头。

(number-to-string 256)
     ⇒ "256"

(number-to-string -23)
     ⇒ "-23"

(number-to-string -23.5)
     ⇒ "-23.5"

int-to-string 是此函数的半过时别名。

另请参阅格式化字符串中的函数格式。

Function: string-to-number string &optional base 

该函数返回字符串中字符的数值。 如果 base 不是 nil,它必须是 2 到 16(含)之间的整数,并且整数在该基数中转换。 如果 base 为 nil,则使用 base 10。 浮点转换仅适用于十进制; 我们还没有为浮点数实现其他基数,因为那会做更多的工作并且似乎没有用。 如果 string 看起来像一个整数,但它的值太大而无法放入 Lisp 整数,则 string-to-number 返回一个浮点结果。

解析会跳过字符串开头的空格和制表符,然后读取尽可能多的字符串,因为它可以解释为给定基数中的数字。 (在某些系统上,它会忽略开头的其他空格,而不仅仅是空格和制表符。)如果字符串不能解释为数字,则此函数返回 0。

  (string-to-number "256")
	   ⇒ 256
  (string-to-number "25 is a perfect square.")
	   ⇒ 25
  (string-to-number "X256")
	   ⇒ 0
  (string-to-number "-4.5")
	   ⇒ -4.5
  (string-to-number "1e5")
	   ⇒ 100000.0

string-to-int 是此函数的过时别名。

Function: char-to-string character 

这个函数返回一个包含一个字符的新字符串,character。 这个函数是半过时的,因为函数字符串更通用。 请参阅创建字符串。

Function: string-to-char string 

此函数返回字符串中的第一个字符。 这与 (aref string 0) 基本相同,只是如果字符串为空则返回 0。 (当字符串的第一个字符为空字符时,该值也为 0,ASCII 码为 0。)如果它看起来没有足够的用处,可能会被淘汰。保留。

以下是一些可以转换为字符串或从字符串转换的其他函数:

concat

此函数将向量或列表转换为字符串。 请参阅创建字符串。

vconcat

此函数将字符串转换为向量。 请参阅向量函数。

append

此函数将字符串转换为列表。 请参阅构建缺点单元格和列表。

byte-to-string

该函数将一个字节的字符数据转换为一个单字节字符串。 请参阅转换文本表示。

4.7 格式化字符串

格式化是指通过替换常量字符串中不同位置的计算值来构造字符串。 这个常量字符串控制其他值的打印方式,以及它们出现的位置; 它被称为格式字符串。

格式化对于计算要显示的消息通常很有用。 事实上,函数 message 和 error 提供了与这里描述的相同的格式化特性; 它们与 format-message 的区别仅在于它们如何使用格式化结果。

Function: format string &rest objects 

此函数返回一个等于字符串的字符串,用相应对象的编码替换任何格式规范。 参数对象是要格式化的计算值。

字符串中的字符(格式规范除外)直接复制到输出中,包括它们的文本属性(如果有)。 格式规范的任何文本属性都被复制到参数对象的生成字符串表示中。

输出字符串不需要重新分配。 例如,如果 x 是字符串 “foo”,则表达式 (eq x (format x)) 和 (eq x (format “%s” x)) 可能都产生 t。

Function: format-message string &rest objects 

此函数的作用类似于格式,除了它还根据 text-quoting-style 的值转换字符串中的任何重音符 (`) 和撇号 (‘)。

通常,格式中的重音和撇号会转换为匹配的弯引号,例如,“Missing `%s’”可能会导致“Missing ‘foo’”。 有关如何影响或禁止此翻译的信息,请参阅文本引用样式。

格式规范是以“%”开头的字符序列。 因此,如果字符串中有 ‘%d’,则格式化函数将其替换为要格式化的值之一(参数对象之一)的打印表示。 例如:

(format "The value of fill-column is %d." fill-column)
     ⇒ "The value of fill-column is 72."

由于 format 将 ‘%’ 字符解释为格式规范,因此您永远不应将任意字符串作为第一个参数传递。 当字符串由一些 Lisp 代码生成时尤其如此。 除非已知字符串不包含任何 ‘%’ 字符,否则将下面描述的“%s”作为第一个参数传递,将字符串作为第二个参数传递,如下所示:

(format "%s" arbitrary-string)

某些格式规范需要特定类型的值。 如果您提供的值不符合要求,则会发出错误信号。

以下是有效格式规范表:

‘%s’

将规范替换为对象的打印表示,不带引号(即使用 princ,而不是 prin1 - 请参阅输出函数)。 因此,字符串仅由其内容表示,没有 ‘”’ 字符,符号出现时没有 ‘' 字符。

如果对象是字符串,则将其文本属性复制到输出中。 ‘%s’ 本身的文本属性也被复制,但对象的文本属性优先。

‘%S’

用引用的对象的打印表示替换规范(即,使用 prin1 - 请参阅输出函数)。 因此,字符串包含在 ‘”’ 字符中,并且 ‘' 字符在必要时出现在特殊字符之前。

‘%o’ 

将规范替换为整数的以 8 为基数的表示形式。 负整数的格式与平台相关。 该对象也可以是格式化为整数的浮点数,去掉任何分数。

‘%d’

用带符号整数的以十进制表示的形式替换规范。 该对象也可以是格式化为整数的浮点数,去掉任何分数。

‘%x’ 
‘%X’

用整数的十六进制表示替换规范。 负整数的格式与平台相关。 “%x”使用小写,“%X”使用大写。 该对象也可以是格式化为整数的浮点数,去掉任何分数。

‘%c’

用给定值的字符替换规范。

‘%e’

将规范替换为浮点数的指数表示法。

‘%f’

将规范替换为浮点数的小数点表示法。

‘%g’

使用指数表示法或小数点表示法将规范替换为浮点数的表示法。 如果指数小于 -4 或大于或等于精度(默认值:6),则使用指数表示法。 默认情况下,从结果的小数部分中删除尾随零,并且仅当小数点字符后跟数字时才会出现小数点字符。

‘%%’

用单个“%”替换规范。 此格式规范的不同之处在于它的唯一形式是普通的 ‘%%’ 并且它不使用值。 例如,(格式“%% %d”30)返回“%30”。

任何其他格式字符都会导致“无效格式操作”错误。

以下是几个示例,它们假定典型的文本引用样式设置:

(format "The octal value of %d is %o,
	   and the hex value is %x." 18 18 18)
     ⇒ "The octal value of 18 is 22,
	   and the hex value is 12."

(format-message
 "The name of this buffer is ‘%s’." (buffer-name))
     ⇒ "The name of this buffer is ‘strings.texi’."

(format-message
 "The buffer object prints as `%s'." (current-buffer))
     ⇒ "The buffer object prints as ‘strings.texi’."

默认情况下,格式规范对应于对象的连续值。 因此,字符串中的第一个格式规范使用第一个这样的值,第二个格式规范使用第二个这样的值,依此类推。 任何额外的格式规范(那些没有对应值的)都会导致错误。 任何要格式化的额外值都将被忽略。

格式规范可以有一个字段编号,它是紧跟在初始“%”之后的十进制数字,后跟一个文字美元符号“$”。 它导致格式规范将参数转换为给定的数字而不是下一个参数。 字段编号从 1 开始。格式可以包含编号或未编号格式规范,但不能同时包含两者,除了 ‘%%’ 可以与编号规范混合。

(format "%2$s, %3$s, %%, %1$s" "x" "y" "z")
     ⇒ "y, z, %, x"

在 ‘%’ 和任何字段编号之后,您可以放置​​某些标志字符。

标志“+”在非负数之前插入一个加号,因此它总是有一个符号。 作为标志的空格字符在非负数之前插入一个空格。 (否则,非负数从第一个数字开始。)这些标志可用于确保非负数和负数使用相同的列数。 除了 ‘%d’、’%e’、’%f’、’%g’ 之外,它们被忽略,如果同时使用了这两个标志,则 ‘+’ 优先。

标志“#”指定了一种替代形式,它取决于所使用的格式。 对于“%o”,它确保结果以“0”开头。 对于“%x”和“%X”,它在非零结果前面加上“0x”或“0X”。 对于“%e”和“%f”,“#”标志意味着即使精度为零也包括小数点。 对于“%g”,它始终包含一个小数点,并且还强制将小数点后的任何尾随零留在原处,否则它们将被删除。

标志“0”确保填充由“0”字符而不是空格组成。 对于“%s”、“%S”和“%c”等非数字规范字符,该标志将被忽略。 这些规范字符接受“0”标志,但仍用空格填充。

标志 ‘-’ 导致按宽度插入的任何填充(如果指定)插入右侧而不是左侧。 如果同时存在“-”和“0”,则忽略“0”标志。

(format "%06d is padded on the left with zeros" 123)
     ⇒ "000123 is padded on the left with zeros"

(format "'%-6d' is padded on the right" 123)
     ⇒ "'123   ' is padded on the right"

(format "The word '%-7s' actually has %d letters in it."
	"foo" (length "foo"))
     ⇒ "The word 'foo    ' actually has 3 letters in it."

规范可以有一个宽度,它是出现在任何字段编号和标志之后的十进制数。 如果对象的打印表示包含的字符少于此宽度,则格式会使用填充对其进行扩展。 宽度引入的任何填充通常由左侧插入的空格组成:

(format "%5d is padded on the left with spaces" 123)
     ⇒ "  123 is padded on the left with spaces"

如果宽度太小,格式不会截断对象的打印表示。 因此,您可以使用宽度来指定列之间的最小间距,而不会丢失信息。 在以下两个示例中,’%7s’ 指定最小宽度为 7。在第一种情况下,代替 ‘%7s’ 插入的字符串只有 3 个字母,并且需要 4 个空格作为填充。 在第二种情况下,字符串“specification”是 13 个字母宽但不会被截断。

(format "The word '%7s' has %d letters in it."
	  "foo" (length "foo"))
     ⇒ "The word '    foo' has 3 letters in it."
(format "The word '%7s' has %d letters in it."
	  "specification" (length "specification"))
     ⇒ "The word 'specification' has 13 letters in it."

所有规范字符都允许在字段编号、标志和宽度(如果存在)之后使用可选精度。 精度是小数点“。” 后跟一个数字字符串。 对于浮点规范(’%e’ 和 ‘%f’),精度指定要显示小数点后的位数; 如果为零,则小数点本身也被省略。 对于 ‘%g’,精度指定要显示多少有效数字(有效数字是小数点之前的第一个数字和它之后的所有数字)。 如果 %g 的精度为零或未指定,则将其视为 1。对于 ‘%s’ 和 ‘%S’,精度会将字符串截断为给定宽度,因此 ‘%.3s’ 仅显示前三个字符对象的表示。 对于其他规范字符,精度的影响是 printf 系列的本地库函数产生的。

如果您打算稍后在格式化字符串上使用 read 来检索格式化值的副本,请使用允许 read 重建值的规范。 要以这种可逆方式格式化数字,您可以使用 ‘%s’ 和 ‘%S’,只格式化整数,你也可以使用 ‘%d’,只格式化非负整数,你也可以使用 ‘#x%x’ 和’#o​​%o’。 其他格式可能有问题; 例如,’%d’ 和 ‘%g’ 可能会错误处理 NaN 并且可能会丢失精度和类型,而 ‘#x%x’ 和 ‘#o%o’ 可能会错误处理负整数。 请参阅输入函数。

本节中描述的函数接受一组固定的规范字符。 下一节描述了一个函数 format-spec,它可以接受自定义规范字符,例如 ‘%a’ 或 ‘%z’。

4.8 自定义格式字符串

有时允许用户和 Lisp 程序等通过自定义格式控制字符串来控制某些文本的生成方式很有用。 例如,格式字符串可以控制如何显示某人的名字、姓氏和电子邮件地址。 使用上一节中描述的函数格式,格式字符串可能类似于“%s %s <%s>”。 然而,这种方法很快变得不切实际,因为可能不清楚哪个规范字符对应于哪条信息。

对于这种情况,更方便的格式字符串类似于“%f %l <%e>”,其中每个规范字符携带更多语义信息,并且可以相对于其他规范字符轻松重新排列,从而使此类格式字符串更容易通过以下方式定制用户。

本节中描述的函数 format-spec 执行与 format 类似的功能,不同之处在于它对使用任意规范字符的格式控制字符串进行操作。

Function: format-spec template spec-alist &optional ignore-missing split 

此函数根据在 spec-alist 中指定的转换返回从格式字符串模板生成的字符串,该字符串是形式(字母 . 替换)的 alist(参见关联列表)。 格式化结果字符串时,模板中的每个规范 %letter 将被替换替换。

模板中的字符(格式规范除外)直接复制到输出中,包括它们的文本属性(如果有)。 格式规范的任何文本属性都将复制到它们的替换位置。

使用 alist 指定转换会产生一些有用的属性:

如果 spec-alist 包含的唯一字母键多于模板中唯一规范字符的数量,则简单地忽略未使用的键。 如果 spec-alist 包含多个具有相同字母的关联,则使用最接近列表开头的关联。 如果 template 多次包含相同的规范字符,则在 spec-alist 中找到的相同替换将用作所有该字符替换的基础。 模板中规范的顺序不必与规范列表中的关联顺序相对应。

可选参数 ignore-missing 指示如何处理模板中未在 spec-alist 中找到的规范字符。 如果它为 nil 或省略,则函数发出错误信号; 如果忽略,则将这些格式规范逐字保留在输出中,包括它们的文本属性(如果有); 如果是删除,则从输出中删除这些格式规范; 任何其他非 nil 值都像忽略一样处理,但任何出现的 ‘%%’ 也会逐字保留在输出中。

如果可选参数 split 不为 nil,则 format-spec 将根据执行替换的位置将结果拆分为字符串列表,而不是返回单个字符串。 例如:

  (format-spec "foo %b bar" '((?b . "zot")) nil t)
	   ⇒ ("foo " "zot" " bar")

format-spec 接受的格式规范的语法与 format 接受的语法相似,但并不完全相同。 在这两种情况下,格式规范都是以“%”开头并以“s”等字母结尾的字符序列。

与为一组固定的规范字符分配特定含义的格式不同,格式规范接受任意规范字符并平等对待它们。 例如:

 (setq my-site-info
	(list (cons ?s system-name)
	      (cons ?t (symbol-name system-type))
	      (cons ?c system-configuration)
	      (cons ?v emacs-version)
	      (cons ?e invocation-name)
	      (cons ?p (number-to-string (emacs-pid)))
	      (cons ?a user-mail-address)
	      (cons ?n user-full-name)))

 (format-spec "%e %v (%c)" my-site-info)
      ⇒ "emacs 27.1 (x86_64-pc-linux-gnu)"

 (format-spec "%n <%a>" my-site-info)
      ⇒ "Emacs Developers <emacs-devel@gnu.org>"

格式规范可以在 ‘%’ 之后立即包含任意数量的以下标志字符,以修改替换的各个方面。

‘0’

此标志导致由宽度指定的任何填充由“0”字符而不是空格组成。

‘-’

此标志会导致将宽度指定的任何填充插入右侧而不是左侧。

‘<’

如果指定,此标志会导致替换在左侧被截断到给定的宽度和精度。

‘>’

如果指定,此标志会导致在给定宽度的右侧截断替换。

‘^’

此标志将替换的文本转换为大写(请参阅 Lisp 中的大小写转换)。

‘_’

此标志将替换的文本转换为小写(请参阅 Lisp 中的大小写转换)。

使用矛盾标志(例如,大写和小写)的结果是未定义的。

与格式一样,格式规范可以包括宽度(出现在任何标志之后的十进制数)和精度(小数点“。”)。 后跟出现在任何标志和宽度之后的十进制数。

如果替换包含的字符少于其指定宽度,则在左侧填充:

(format-spec "%8a is padded on the left with spaces"
	     '((?a . "alpha")))
     ⇒ "   alpha is padded on the left with spaces"

如果替换包含的字符数超过其指定的精度,则会在右侧截断:

(format-spec "%.2a is truncated on the right"
	       '((?a . "alpha")))
     ⇒ "al is truncated on the right"

这是一个更复杂的示例,它结合了上述几个功能:

 (setq my-battery-info
	(list (cons ?p "73")      ; Percentage
	      (cons ?L "Battery") ; Status
	      (cons ?t "2:23")    ; Remaining time
	      (cons ?c "24330")   ; Capacity
	      (cons ?r "10.6")))  ; Rate of discharge

 (format-spec "%>^-3L : %3p%% (%05t left)" my-battery-info)
      ⇒ "BAT :  73% (02:23 left)"

 (format-spec "%>^-3L : %3p%% (%05t left)"
	       (cons (cons ?L "AC")
		     my-battery-info))
      ⇒ "AC  :  73% (02:23 left)"

正如本节中的示例所示,格式规范通常用于有选择地格式化各种不同的信息。 这在提供用户可自定义格式字符串的程序中很有用,因为用户可以选择使用常规语法并以任何所需的顺序仅格式化程序提供的信息的子集。

4.9 Lisp 中的大小写转换

字符大小写函数改变单个字符或字符串内容的大小写。 这些函数通常只转换字母字符(字母 ‘A’ 到 ‘Z’ 和 ‘a’ 到 ‘z’,以及非 ASCII 字母); 其他字符不变。 您可以通过指定案例表来指定不同的案例转换映射(请参阅案例表)。

这些函数不会修改作为参数传递给它们的字符串。

下面的示例使用字符“X”和“x”,它们的 ASCII 码分别为 88 和 120。

Function: downcase string-or-char 

此函数将 string-or-char(应该是字符或字符串)转换为小写。

当 string-or-char 是字符串时,此函数返回一个新字符串,其中参数中的每个大写字母都转换为小写。 当 string-or-char 为字符时,该函数返回对应的小写字符(整数); 如果原始字符是小写字母,或者不是字母,则返回值等于原始字符。

  (downcase "The cat in the hat")
	   ⇒ "the cat in the hat"

  (downcase ?X)
	   ⇒ 120

Function: upcase string-or-char 

此函数将 string-or-char(应该是字符或字符串)转换为大写。

当 string-or-char 为字符串时,此函数返回一个新字符串,其中参数中的每个小写字母都转换为大写。 当 string-or-char 为字符时,该函数返回对应的大写字符(整数); 如果原始字符是大写字母,或者不是字母,则返回值等于原始字符。

  (downcase "The cat in the hat")
	   ⇒ "the cat in the hat"

  (downcase ?X)
	   ⇒ 120

Function: upcase string-or-char 

此函数将字符串或字符大写。 如果 string-or-char 是字符串,则该函数返回一个新字符串,其内容是 string-or-char 的副本,其中每个单词都已大写。 这意味着每个单词的第一个字符转换为大写,其余的转换为小写。

一个词的定义是在当前句法表中分配给词构成句法类的任何连续字符序列(参见句法类表)。

当 string-or-char 是一个字符时,这个函数的作用与大写相同。

  (upcase "The cat in the hat")
	   ⇒ "THE CAT IN THE HAT"

  (upcase ?x)
	   ⇒ 88

Function: capitalize string-or-char 

如果 string-or-char 是字符串,则此函数将 string-or-char 中单词的首字母大写,而不更改除首字母以外的任何字母。 它返回一个新字符串,其内容是 string-or-char 的副本,其中每个单词的首字母都已转换为大写。

一个词的定义是在当前句法表中分配给词构成句法类的任何连续字符序列(参见句法类表)。

当 upcase-initials 的参数是字符时,upcase-initials 的结果与 upcase 相同。

  (capitalize "The cat in the hat")
	   ⇒ "The Cat In The Hat"


  (capitalize "THE 77TH-HATTED CAT")
	   ⇒ "The 77th-Hatted Cat"


  (capitalize ?x)
	   ⇒ 88

请注意,大小写转换不是代码点的一对一映射,结果的长度可能与参数的长度不同。 此外,由于传递字符会强制返回类型为字符,因此函数无法执行正确的替换,并且与处理单字符字符串相比,结果可能会有所不同。 例如:

(upcase "fi")  ; note: single character, ligature "fi"
     ⇒ "FI"

(upcase ?fi)
     ⇒ 64257  ; i.e. ?fi

为避免这种情况,必须首先使用字符串函数将字符转换为字符串,然后再将其传递给其中一个大小写函数。 当然,不能对结果的长度做出任何假设。

这种特殊情况的映射取自特殊大写、特殊小写和特殊标题,请参阅字符属性。

有关比较字符串的函数,请参见字符和字符串的比较; 其中一些忽略大小写差异,或者可以选择忽略大小写差异。

4.10 案例表

您可以通过安装特殊案例表来自定义案例转换。 大小写表指定大写和小写字母之间的映射。 它影响 Lisp 对象的大小写转换函数(参见上一节)和应用于缓冲区中文本的那些(参见大小写更改)。 每个缓冲区都有一个案例表; 还有一个标准案例表,用于初始化新缓冲区的案例表。

案例表是一个字符表(参见 Char-Tables),其子类型是案例表。 此字符表将每个字符映射到相应的小写字符。 它有三个额外的插槽,其中包含相关的表:

upcase

大写表将每个字符映射到相应的大写字符。

canonicalize

canonicalize 表将所有与大小写相关的字符集映射到该集的特定成员中。

equivalences

等价表将一组与大小写相关的字符中的每个字符映射到该集中的下一个字符。

在简单的情况下,您只需要指定小写的映射即可; 三个相关的表格将根据该表格自动计算。

对于某些语言,大小写字母不是一一对应的。 可能有两个不同的小写字母具有相同的大写字母。 在这些情况下,您需要为小写和大写指定映射。

额外的表 canonicalize 将每个字符映射到一个规范等效项; 通过大小写转换相关的任何两个字符都具有相同的规范等效字符。 例如,由于 ‘a’ 和 ‘A’ 通过大小写转换相关,因此它们应该具有相同的规范等效字符(它们应该是 ‘a’ 或者它们都应该是 ‘A’)。

额外的表等价是一个循环置换每个等价类(具有相同规范等价的字符)的映射。 (对于普通的 ASCII,这会将“a”映射到“A”,将“A”映射到“a”,对于每组等效字符也是如此。)

构造案例表时,可以为canonicalize提供nil; 然后 Emacs 从小写和大写映射中填充这个槽。 您还可以为等价提供 nil ; 然后 Emacs 从 canonicalize 填充这个槽。 在实际使用的案例表中,这些组件是非零的。 不要试图在没有指定规范化的情况下指定等价。

以下是处理案例表的函数:

Function: case-table-p object

如果 object 是有效的 case 表,则此谓词返回非 nil。

Function: set-standard-case-table table

此函数使 table 成为标准案例表,因此它将在随后创建的任何缓冲区中使用。

Function: standard-case-table

这将返回标准案例表。

Function: current-case-table

此函数返回当前缓冲区的案例表。

Function: set-case-table table

这会将当前缓冲区的案例表设置为表。

Macro: with-case-table table body

with-case-table 宏保存当前 case 表,使 table 成为当前 case 表,评估 body 形式,最后恢复 case 表。 返回值是正文中最后一个表单的值。 即使在通过 throw 或 error 异常退出的情况下也会恢复 case 表(请参阅非本地退出)。

一些语言环境修改了 ASCII 字符的大小写转换; 例如,在土耳其语环境中,ASCII 大写字母 I 被缩减为土耳其语无点 i (‘ı’)。 这可能会干扰需要普通 ASCII 大小写转换的代码,例如基于 ASCII 的网络协议的实现。 在这种情况下,请使用带有变量 ascii-case-table 的 with-case-table 宏,该变量存储 ASCII 字符集的未修改大小写表。

Variable: ascii-case-table

ASCII 字符集的大小写表。 这不应被任何语言环境设置修改。

以下三个函数是定义非 ASCII 字符集的包的方便子例程。 他们修改指定的案例表case-table; 他们还修改了标准语法表。 请参阅语法表。 通常您会使用这些函数来更改标准案例表。

Function: set-case-syntax-pair uc lc case-table

该函数指定一对对应的字母,一个大写一个小写。

Function: set-case-syntax-delims l r case-table

此函数使字符 l 和 ra 匹配一对不改变大小写的分隔符。

Function: set-case-syntax char syntax case-table

此函数使 char 不区分大小写,具有语法语法。

Command: describe-buffer-case-table

此命令显示当前缓冲区的案例表内容的描述。

马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/advanceflow/elisp.git
git@gitee.com:advanceflow/elisp.git
advanceflow
elisp
Elisp
main

搜索帮助