random text

本文介绍了一种使用Hash Table实现的文本生成算法,包括读取文本、处理标点符号、更新Hash Table以及随机选择下一个单词的过程。通过实例演示了如何通过函数调用来生成文本并实现语法闭包特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(defparameter *words* (make-hash-table :size 10000))
(defconstant maxword 100)


(defun punc (c)
  (case c
    (#\. '|.|) (#\, '|,|) (#\; '|;|)
    (#\! '|!|) (#\? '|?|)))

;;当前的字符串为symb,而它前面的字符串为prev,首先判断是否有如下个(prev . (symb . n))如果有的话,n+1,没有就
;;添加一位(prev . (symb . n)),在最后会把当前的symb设置为prev,因为
(let ((prev  '|.|))
  (defun see (symb)
    (let ((pair (assoc symb (gethash prev *words*))))
      (if (null pair)
	  (push (cons symb 1) (gethash prev *words*)) ;;如果没有的话,就在相应位置赋值
	  (incf (cdr pair))))
    (setf prev symb)))           ;语法闭包,只要外面有这个函数的引用,它里面的值就可以访问.因为这样你才能够把当前处理过的作为prev并且在下一次比较时能够引用到。因为我们没有如c语言中你在函数外面创建一个变量,每一次我都可以通过它作为一个中转站来存储值,并且用于下一次的比较。忘了c++中如果想调用上一次执行中的值该是如何实现?是定义一个toplevel的变量来接收吗?还是跟这个一样,语法闭包,只要有这个函数的引用它里面的值就可以利用。

(defun read-text (pathname)
  (with-open-file (s pathname :direction :input)
    (let ((buffer (make-string maxword)) ;定义一个buffer大小为10000
	  (pos 0))
      (do ((c (read-char s nil :eof)
	      (read-char s nil :eof)))
	  ((eql c :eof))
;;第一progn就是实现一个单词的整体输入,因为当碰见分隔符的时候才写入停止。
	(if (or (alpha-char-p c) (char= c #\'))
	    (progn                         ;如果是字符或者'的话就直接写入buffer
	      (setf (aref buffer pos) c)   ;设置buffer在pos的值为C
	      (incf pos))                  ;因为上面已经添加了值,所以buffer的pos+1
	    (progn
	      (unless (zerop pos)          ;如果不是起始位置
		(see (intern (string-downcase        ;变为小写
			      (subseq buffer 0 pos)))) ;取从0到pos的子串
		(setf pos 0))              ;比如see过half以后,C为空格,执行下面一段逻辑为nil
	      (let ((p (punc c)))          ;为了处理那些连续的标点符号比如,;.
		(if p (see p)))))))))

;;;n是总共就循环这么多次,首先我们先给他一个prev,也就是key,然后你根据这个key去调用random-next.意思就是
;;;随机选出来一个它的value中的car做为下一个后继,然后再用这个后继重复前面的操作。总共次数是n.
(defun random-next (prev)
  (let* ((choices (gethash prev *words*));;把prev的value都放到choices里面
         (i (random (reduce #'+ choices ;;把choices这些个alist的累加后面的cdr,得到一个随机值
                            :key #'cdr))))
    (dolist (pair choices)   ;例如(gethash '|d| *words*) ((|in| . 2) (|round| . 2) (|,| . 2))
      (if (minusp (decf i (cdr pair)));;如果choices中alist对象car大于随机值,就返回它的key.
          (return (car pair))))))
(defun generate-text (n &optional (prev '|.|))
  (if (zerop n)
      (terpri)  ;换行,如果已经是行的开头的话,没有任何效果
      (let ((next (random-next prev)))
        (format t "~A " next)
        (generate-text (1- n) next))))

CL-USER> (assoc :a (list (cons :a 1) (cons :b 2)))
(:A . 1)
CL-USER> (intern "help")                        ;;它为啥要用这种形式呢?
|help|
CL-USER> (incf (cdr (cons :a 1)))
2
CL-USER> (aref "string" 2)
#\r
CL-USER> (subseq "string" 1 3)
"tr"
CL-USER> (defun test(n)
	   (unless (< n 4)
	     (format t "unless1")
	     (format t "unless2")))
TEST
CL-USER> (test 6)
unless1unless2
NIL
CL-USER>  (reduce #'+ (list (cons 2 3) (cons 4 5 )) :key #'cdr)
8

(see (intern (string-downcase       
     (subseq buffer 0 pos))))

是否可以变为下面这个形式呢?

(see   (subseq buffer 0 pos)) 

因为hash-table是按eql进行相等检查的,如果你用第二种方式,键与我们输入的形式就永远不会相等。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值