一个很有意思的问题: 揭示了计算机程序问题的一般处理思路

半城伤御伤魂 提交于 2020-03-02 08:32:25

一个很有意思的问题: 揭示了计算机程序问题的一般处理思路

===

问题标题: 如何统计汉字的字数? 问题内容: 我想统计: "什么样的问题在 oschina 算是一个好问题?" 这个句子里面以oschina为分割总共有三部分: 什么样的问题在+ oschina +算是一个好问题? 现在想知道oschina前面有几个汉字?oschina有几个英文?oschina后面有几个汉字?不要直接去查找oschina字符串去计算啊,可以当作oschina是某个未知的英文单词,如何统计出来呢? ps.楼下的说我的表达能力有问题,看来我确实没有表达清楚:)再补充一下问题。 问题来源: http://www.oschina.net/question/583303_122530

===

这个问题的关键是如何让计算机区分汉字和英文, 具体分析就要涉及到中文和英文在计算机内部的表示方式, 那么一切以数字为准, 先把这段数据转换为数字格式, 如下代码:

(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> 

我们看到, 每一个文字字符都被转化为一个数字值, 这个数字值就是计算机内部对这个字符的表示, 也就是说数字值和文字字符之间存在着一种对应关系. 其实到这里问题基本就解决一多半了, 剩下的就是对这些数字值的操作了.

更简单的语句是:

(defun 字符串-数字向量 (字符串)	
  (map 'vector #'char-code 字符串))

与前面第一个函数的区别是, 本函数返回的结果是一个向量, 试试看:

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> 

再试试日文:

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> 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!