(defstruct bufvec (start -1) (used -1) (new -1) (end -1))(defun bref (buf n)(svref (buf-vec buf)(mod n (length (buf-vec buf)))));;;扩展setf方法,注意下面调用的方式
(defun (setf bref) (val buf n)(setf (svref (buf-vec buf)(mod n (length (buf-vec buf))))val))(defun new-buf (len)(make-buf :vec (make-array len)))(defun buf-insert (x b)(setf (bref b (incf (buf-end b))) x))(defun buf-pop (b)(prog1 (bref b (incf (buf-start b)))(setf (buf-used b) (buf-start b)(buf-new  b) (buf-end   b))))(defun buf-next (b)(when (< (buf-used b) (buf-new b))(bref b (incf (buf-used b)))))(defun buf-reset (b)(setf (buf-used b) (buf-start b)(buf-new  b) (buf-end   b)))
;;;都设置成-1,为了实现对buffer的清空
(defun buf-clear (b)(setf (buf-start b) -1 (buf-used  b) -1(buf-new   b) -1 (buf-end   b) -1))
;;只有一种情况buf-used为-1,说明到文件结束时,刚读入到buffer的字符都匹配,未出现pop逻辑,故-1+1=0,也就是从头开始princ.
(defun buf-flush (b str)(do ((i (1+ (buf-used b)) (1+ i)))((> i (buf-end b)))(princ (bref b i) str)))

(setf bref) 它重载了setf方法,为了是mod n 然后得到ring buffer。只有在insert的时候才调用了这个setf方法。n是buf-end +1之后的值,length最后的结果是buffer的长度,是个定值。比方说只剩下第二个b的时候,buf-end = 3. (3+1) mod 4 = 0,所以接下来的a就加入到了第一个位置。
buf-insert 关键就是里面的扩展的setf 方法。
buf-next只有在输入的时候是从buffer里面来的时候才用buf-next。它是先比较当前位置used是否小于buf-new,如果是就把下面那个输出来。所以说第二b仍旧会读出来进行匹配测试,当它执行完以后,然后再call buf-next的话,发现used跟new已经相等了,所以只能是read里面读取数据了。
buf-pop    它是从栈出来,只有执行了princ才会输出到out里面。所以说你看zerop pos首先是princ,然后才是出栈。

buf-flush  是为了解决一种情况:假设pattern为baro,现在文本中最后几个字符为bar。因为整个循环是到文件尾结束,现在bar还在buffer里面就结束了,所以将会显示不出来。其他情况的话buf-flush要不要没影响。

(defun file-subst (old new file1 file2)(with-open-file (in file1 :direction :input)(with-open-file (out file2 :direction :output:if-exists :supersede)(stream-subst old new in out))))(defun stream-subst (old new in out)(let* ((pos 0)(len (length old))            (buf (new-buf len))           ;buffer的长度跟pattern串长度一样,(from-buf nil))(do ((c (read-char in nil :eof)    ;初始时读取一个字符(or (setf from-buf (buf-next buf))   ;因为有短路现象,要么从buffer中读取,要不从流中。(read-char in nil :eof))))((eql c :eof))                   ;循环结束条件是碰到了结尾(cond ((char= c (char old pos))    ;如果读入的字符等于old中的一个字符(incf pos)                  ;pos+1,因为凡是匹配成功的话,pattern中的指标就要加+指到下一位;;内部cond判断两次(cond ((= pos len)            ; 3  因为上面pos已经加1了,所以说只需相等就行了。(princ new out)     ;把它输出来(setf pos 0)        ;pos 变为0(buf-clear buf))    ;buffer 清空((not from-buf)         ; 2 (buf-insert c buf))))((zerop pos)                   ; 1(princ c out)(when from-buf(buf-pop buf)(buf-reset buf)))(t                             ; 4(unless from-buf(buf-insert c buf))(princ (buf-pop buf) out)(buf-reset buf)(setf pos 0))))(buf-flush buf out)))

start : 当我们pop一个元素,他就会增加,增加buf-stard。
end   :当我们插入一个元素的时候他会增加,先增加buf-end,然后再往这个buf-end里面添加值。
used  : 当我们pop完一个元素,然后就会调用bufnext,他会在里面累加。
new   : 当试着匹配buffer里面的字符时,开始调用used/new,一旦buffer中匹配开始,new就会绑定到end,因为end就相当于是buffer里面最后一个元素,然后调用buf-next,进行迭代匹配,直到used=new。也就是说一旦检测buffer的话,会把buffer里面所有的都试着匹配一遍,然后才会开始接受从read中读取。

1:ring buffer空间只要跟pattern一样就行。
2:短路现象中,在b-a-r的过程中因为虽然这个时候buf-used< buf-new当时取到的值为nil,所以仍旧是从流中读取
from-buf意思就是从buf里面读取数据成功。
3:什么时候第一次给used/new赋值的呢?也就是在第一次pop的时候进行reset的时候才会给used/new进行赋值。就像图5,因为前面的时候used/new都是-1,所以也都是按流读入的。

Case1:zerop pos 首先表示的是一个新的匹配,并且前面没有字符匹配成功的话,就把他输出来。如u/s直接输出来了。都没有到buffer里面还有一种情况就是这个字符已经在buffer里面了,但是前面没有字符匹配成功,他就需要从buffer中出来,并且重新设置pos为0(指向pattern的第一个位置)
Case2:当匹配开始,也就是说前面有字符匹配已经匹配上了。当读入的字符不是来自于buffer(from-buf 为假),就将字符输入到buffer里面。pos 指定到old string上面。当字符与在pattern string的pos +1值一样时,说明整个串匹配成功。
Case3:pos + 1 跟new string的长度一样,并且匹配在这个位置的元素匹配成功,就输出一个新的string。重新把pattern匹配的起始位置设置为0,因为你已经匹配成功了,下一个再进行匹配的话,只能是从头开始。把buffer里面的东西请空。  因为先处理完buffer里面的东西,才会继续从读入新的值。比如当你匹配a弹出的时候,他会再(setf from-buf (buf-next buf))
Case4:匹配到中途在这个位置不匹配了。pop第一个字符出栈,然后reset,并且设置pos从pattern头开始重新匹配。因为你输入的时候就是两种情况输入的,一个是读进去,一个是from-buf.所以在你处理的时候也同样是两种情况处理。

首先按照匹配是否成功,然后再按照是否来自于文件输入或者是buffer部分读取。

CL-USER> (char "string" 1)
#\t
CL-USER> (new-buf 6)
#S(BUF :VEC #(0 0 0 0 0 0) :START -1 :USED -1 :NEW -1 :END -1)
CL-USER> (length (buf-vec (new-buf 6)))
6
CL-USER> (file-subst " th" "z" "d:/emacs/string.txt" "d:/emacs/stringold.txt")
NIL

string substitution相关推荐

  1. 如何超越console.log并充分利用浏览器的调试控制台

    by Gilad Dayagi 通过吉拉德·达亚吉 The console object is a very useful feature of browsers that has been arou ...

  2. GNU make manual 翻译( 一百一十九)

    继续翻译 Each target specified must match the target pattern; a warning is issued for each target that d ...

  3. 使用getopts处理长和短命令行选项

    我希望使用我的shell脚本来调用命令行选项的长短形式. 我知道可以使用getopts ,但是像在Perl中一样,我无法对shell进行同样的操作. 关于如何完成此操作的任何想法,这样我就可以使用以下 ...

  4. 如何干掉恶心的 SQL 注入?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | rrd.me/fKXEa 简介 文章主要内容包 ...

  5. 跟我一起写udev规则

    目录 介绍        关于本文档       更新历史 概念      术语: devfs, sysfs, nodes, etc.      为什么?      内置固定命名设计 编写规则     ...

  6. console 立即输出 调试_Javascript调试利器console的使用

    一.Console API Console.assert() 判断第一个参数是否为真,false的话抛出异常并且在console输出相应信息. Console.count() 以参数为标识记录调用的次 ...

  7. Awk by Example--转载

    原文地址: http://www.funtoo.org/Awk_by_Example,_Part_1?ref=dzone http://www.funtoo.org/Awk_by_Example,_P ...

  8. 在Eclipse中使用Maven 2.x指南

    1.Maven 2 Repository Eclipse需要知道Maven的本地仓库的路径.所以,类路径变量M2_REPO必须设置.执行以下命令: mvn -Declipse.workspace=&l ...

  9. GNU make manual 翻译( 一百一十四)

    继续翻译 4.10 Multiple Targets in a Rule ===============================A rule with multiple targets is ...

最新文章

  1. html5考试总结300字,期中考心得300字5
  2. 从电视到网络,vivo营销之变
  3. Linux下部署开源版“禅道”项目管理系统
  4. Android Mvp 架构
  5. Java中传值与传地址
  6. 用户体验五要素_Kwai竞品分析-用户体验五要素
  7. 【COCOS CREATOR 系列教程之二】脚本开发篇事件监听、常用函数等示例整合
  8. Python random 模块 - Python零基础入门教程
  9. codeforces MUH and Important Things
  10. javascript设计模式研究学习-设计模式类别
  11. wepyjs小程序组件调用pages页面的方法
  12. 系统更新后mysql用不了中文,Mysql在debian系统中不能插入中文的终极解决方案
  13. Linux上创建SSH隧道
  14. 关于定时器setInterval()累加或者是重叠的问题
  15. Linux 用户必须知道的 14 个常用 Linux 终端快捷键
  16. vimpython配色_你认为最好看的 Vim 配色方案(color scheme)是哪款?
  17. html5 手机剪切板,H5页面在手机端如何实现复制粘贴板功能
  18. 各型号iPhone的屏幕参数 逻辑分辨率 物理分辨率 - iOS Device Display Summary - 更新到iPhone 13系列
  19. 数据库服务:数据库表空间扩容
  20. 青春不只风花雪月更当豪迈向上

热门文章

  1. D-OJ刷题日记:顺序查找验证(将哨兵设在下标高端) 题目编号:1038
  2. 6-Linux查看磁盘、文件剩余或占用空间大小
  3. 别再用智能合约时代的思维,去思考下一代区块链应用
  4. WEB前端.jQuery
  5. jQuery前端验证(四)
  6. java netty 教程,Java NIO框架Netty教程(十七) - Netty4 Hello world
  7. 批量获取微信公众号文章里的图片
  8. k-均值(k-means)聚类
  9. 引用传递(passing by references) 在C语言和C++中的区别
  10. 【C语言】C语言多线程实例之pthread的应用