- 本文翻译自Strings
- 本文内容包括使用Clojure内建的函数和标准库来操作字符串,以及JDK中的相关操作.
- 版权:This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets).
- 源代码在Github上.
目录
- 1 概述
- 2 预备知识
- 3 方法
- 3.1 基础方法
- 3.2 解析复杂字符串
- 3.2.1 正则表达式
- 3.2.2 上下文无关语法
- 3.3 构建复杂的字符串
- 3.3.1 重定向
- 3.3.2 格式化字符串
- 3.3.3 CL-Format
- 4 贡献者
概述
- Clojure中的字符串就是Java字符串.你可以使用Java中的相应方法来对其进行处理.
- Java字符串是不可变的,所以能很方便的在Clojure中使用
- 你不能给Java字符串添加元数据
- Clojure提供一些方便的符号
"foo" java.lang.String #"\d" java.util.regex.Pattern (正则表达式,匹配一个数字) \f java.lang.Character (表示'f')
- 注意: 人类的大脑和计算机之间还是有很大的差异的.所以Java的字符串(UTF-16编码)并不能像人们所认为的那样很好的和字符一一对应.比如说,一个Unicode的位和我们所认为的字符的一位是无法对应的(像韩国 韩语尊宝,这些词由多个字符组成.)同样的,一个Unicode位可能是由2个UTF-16字符组成.
预备知识
一些例子用到了clojure.string,clojure.edn和clojure.pprint.我们假设你的ns宏里面已经包含了如下内容:
(:require [clojure.string :as str] [clojure.edn :as edn] [clojure.pprint :as pp])或者在REPL里面,你需要载入:
(require '[clojure.string :as str]) (require '[clojure.edn :as edn]) (require '[clojure.pprint :as pp])
方法
基础方法
;; 长度计算 (count "0123") ;=> 4 (empty "0123") ;=> false (empty "") ;=> true (str/blank " ") ;=> true ;; 字符串连接 (str "foo" "bar") ;=> "foobar" (str/join ["0" "1" "2"]) ;=> "012" (str/join "." ["0" "1" "2"]) ;=> "0.1.2" ;; 使用Java方法来匹配. ;; ;; 对于下面的情况,你应该更喜欢使用正则表达式.比如,你在进行测试,当失败时需要返回-1. ;; 或者一个字符\o需要转换成字符串或数字. (.indexOf "foo" "oo") ;=> 1 (.indexOf "foo" "x") ;=> -1 (.lastIndexOf "foo" (int \o)) ;=> 2 ;; 字符串截取 (subs "0123" 1) ;=> "123" (subs "0123" 1 3) ;=> "12" (str/trim " foo ") ;=> "foo" (str/triml " foo ") ;=> "foo " (str/trimr " foo ") ;=> " foo" ;; 切分字符串 (seq "foo") ;=> (\f \o \o) (str/split "foo/bar/quux" #"/") ;=> ["foo" "bar" "quux"] (str/split "foo/bar/quux" #"/" 2) ;=> ["foo" "bar/quux"] (str/split-lines "foo bar") ;=> ["foo" "bar"] ;; 大小写转换 (str/lower-case "fOo") ;=> "foo" (str/upper-case "fOo") ;=> "FOO" (str/capitalize "fOo") ;=> "Foo" ;; 转换 (str/escape "foo|bar|quux" {\| "||"}) ;=> "foo||bar||quux" ;; 获得给定编码的字节数组 ;; (输出可能和下面的"3c3660"不同) (.getBytes "foo" "UTF-8") ;=> #;; 解析为keyword (keyword "foo") ;=> :foo ;; 解析为数字 (bigint "20000000000000000000000000000") ;=> 20000000000000000000000000000N (bigdec "20000000000000000000.00000000") ;=> 20000000000000000000.00000000M (Integer/parseInt "2") ;=> 2 (Float/parseFloat "2") ;=> 2.0 ;; 解析为edn,它是Clojure形式的一个子集 (edn/read-string "0xffff") ;=> 65535 ;; 读取Clojure形式的方法. ;; ;; 安全警告:当你无法确保你能100%信任要处理的字符串时,请将*read-eva l*置为false. ;; 从Clojure1.5开始*read-eva l*默认为false,但为了安全起见, ;; 在处理字符串时还是先手动置一下false ;; 因为可能有操作将其置为了true. (binding [*read-eva l* false] (read-string "#\"[abc]\"")) ;=> #"[abc]" 解析复杂字符串
正则表达式
正则表达式增强了字符串匹配.你可以重复匹配,匹配其中之一,等等等等.
- Regex reference
Groups:当我们想匹配多余一个子串时,正则表达式的组就起到了作用. 在正则表达式#”(group-1) (group-2)”中, 第0个组为整个匹配表达式.第1个组从最左边的(开始,第2个组从左起第二个(开始,依次类推.你还可以嵌套组.也可以后续通过$0,$1等来引用组.
- 匹配
;; 简单匹配 (re-find #"\d+" "foo 123 bar") ;=> "123" ;; 匹配不到时会怎样 (re-find #"\d+" "foobar") ;=> nil ;; 对每个组返回第一个满足匹配条件的内容 (re-matches #"(@\w+)\s([.0-9]+)%" "@shanley 19.8%") ;=>["@shanley 19.8%" "@shanley" "19.8"] ;; 返回所有匹配的组的结果 (re-seq #"(@\w+)\s([.0-9]+)%" "@davidgraeber 12.3%,@shanley 19.8%") ;=> (["@davidgraeber 12.3%" "@davidgraeber" "12.3"] ; ["@shanley 19.8%" "@shanley" "19.8"])- 替换
我们使用str/replace来进行替换. 第一个参数是源字符串,下一个是匹配字符串,最后一个是替换的内容.
match / replacement can be: string / string char / char
- 替换
- 匹配
- Regex reference
- 注意: 人类的大脑和计算机之间还是有很大的差异的.所以Java的字符串(UTF-16编码)并不能像人们所认为的那样很好的和字符一一对应.比如说,一个Unicode的位和我们所认为的字符的一位是无法对应的(像韩国 韩语尊宝,这些词由多个字符组成.)同样的,一个Unicode位可能是由2个UTF-16字符组成.
- Clojure中的字符串就是Java字符串.你可以使用Java中的相应方法来对其进行处理.