===程序員
問題標題: 如何統計漢字的字數? 問題內容: 我想統計: "什麼樣的問題在 oschina 算是一個好問題?" 這個句子裏面以oschina爲分割總共有三部分: 什麼樣的問題在+ oschina +算是一個好問題? 如今想知道oschina前面有幾個漢字?oschina有幾個英文?oschina後面有幾個漢字?不要直接去查找oschina字符串去計算啊,能夠看成oschina是某個未知的英文單詞,如何統計出來呢? ps.樓下的說個人表達能力有問題,看來我確實沒有表達清楚:)再補充一下問題。 問題來源: http://www.oschina.net/question/583303_122530函數
===.net
這個問題的關鍵是如何讓計算機區分漢字和英文, 具體分析就要涉及到中文和英文在計算機內部的表示方式, 那麼一切以數字爲準, 先把這段數據轉換爲數字格式, 以下代碼:code
(defparameter *字符串* "什麼樣的問題在 oschina 算是一個好問題?") (defun 字符串-數字(字符串) (dotimes (序數 (length 字符串)) (print (char-code (elt 字符串 序數)))))
執行一下, 結果以下:字符串
CL-USER> (字符串-數字 *字符串*) 20160 20040 26679 30340 38382 39064 22312 32 111 115 99 104 105 110 97 32 31639 26159 19968 20010 22909 38382 39064 65311 NIL CL-USER>
咱們看到, 每個文字字符都被轉化爲一個數字值, 這個數字值就是計算機內部對這個字符的表示, 也就是說數字值和文字字符之間存在着一種對應關係. 其實到這裏問題基本就解決一多半了, 剩下的就是對這些數字值的操做了.get
更簡單的語句是:io
(defun 字符串-數字向量 (字符串) (map 'vector #'char-code 字符串))
與前面第一個函數的區別是, 本函數返回的結果是一個向量, 試試看:lambda
CL-USER> (字符串-數字向量 *字符串*) #(20160 20040 26679 30340 38382 39064 22312 32 111 115 99 104 105 110 97 32 31639 26159 19968 20010 22909 38382 39064 65311) CL-USER>
再試試日文:map
CL-USER> (字符串-數字向量 "日本語:平假名にほんご") #(26085 26412 35821 65306 24179 20551 21517 12395 12411 12435 12372) CL-USER>
如今就一目瞭然了, 這個句子也由適合人類閱讀的形式轉化爲適合計算機閱讀的數字形式了, 代碼寫到這一步, 程序員須要瞭解的知識就是人類和計算機之間的契約了, 如什麼樣的數字表明什麼樣的文字符號等等諸如此類的約定. 咱們通常都知道:程序
0~127 之間的數字表示製表打印控制字符,英文大小寫字符以及英文標點符號, 也就是 ASCII 超過127 的數字表示中文字符和全角標點符號等(若是使用其餘字符集, 那麼就是其餘字符, 如日文)
剩下的操做就是對數字的比較,分類等操做了.
這個問題給咱們的啓示就是, 首先要把問題的表述形式變化爲計算機能理解的數字形式, 而後再去翻找人類和計算機之間已經簽定好的契約, 而後按照契約的規定來分析處理.
目前寫了兩個函數, 簡單區分了一下英文(0~127 的數字)和非英文(大於 127 的數字), 以下:
(defun 字數統計函數 (字符串) (let ((漢字個數 0) (空格個數 0) (英文字母個數 0) (全角問號個數 0) (代碼點 0)) (dotimes (序數 (length 字符串)) (setq 代碼點 (char-code (elt 字符串 序數))) (cond ((= 代碼點 32) (setf 空格個數 (1+ 空格個數))) ((= 代碼點 65311) (setf 全角問號個數 (1+ 全角問號個數))) ((> 代碼點 127) (setf 漢字個數 (1+ 漢字個數))) ((and (> 代碼點 0) (<= 代碼點 127)) (setf 英文字母個數 (1+ 英文字母個數))))) (values "空格個數:" 空格個數 "全角問號個數:"全角問號個數 "漢字個數:" 漢字個數 "英文字母個數" 英文字母個數))) (defun 字數統計函數-映射版 (字符串) (let ((漢字個數 0) (空格個數 0) (英文字母個數 0) (全角問號個數 0)) (map 'vector #'(lambda (代碼點) (cond ((= 代碼點 32) (setf 空格個數 (1+ 空格個數))) ((= 代碼點 65311) (setf 全角問號個數 (1+ 全角問號個數))) ((> 代碼點 127) (setf 漢字個數 (1+ 漢字個數))) ((and (> 代碼點 0) (<= 代碼點 127)) (setf 英文字母個數 (1+ 英文字母個數))))) (map 'vector #'char-code 字符串)) (values "空格個數:" 空格個數 "全角問號個數:"全角問號個數 "漢字個數:" 漢字個數 "英文字母個數" 英文字母個數)))
執行結果以下:
CL-USER> (字數統計函數 *字符串*) "空格個數:" 2 "全角問號個數:" 1 "漢字個數:" 14 "英文字母個數" 7 CL-USER> (字數統計函數-映射版 *字符串*) "空格個數:" 2 "全角問號個數:" 1 "漢字個數:" 14 "英文字母個數" 7 CL-USER>