Clojure专题:字符串处理(一)

2014-11-24 02:45:30 · 作者: · 浏览: 1
  • 本文翻译自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