https://blog.csdn.net/yxp_xa/article/details/72466333
在1956 年,一位名叫 Stephen Kleene 的数学科学家,发表了一篇《神经网事件的表示法》的论文,论文中采用正则集合的数学符号来模拟人类神经系统的工作原理。后来人们将这一成果转化到计算机算法中,将其变成了一门文本搜索和处理的语言。
正则表达式(Regular Express ),可以按字面意思理解,正确的符合规则的表式。
在 CAD 的二次开发中,简单的文字匹配可以用 Lisp 自带的 wcmatch 函数,但是这个函数返回值只有 T 或 NIL。 如果需要返回匹配后的相关字符时,或者稍微复杂一点的文字匹配, wcmatch 就无能为力了。
深入地学习正则表达式的语法还是有些难度的,我用的是偷懒的办法,只写最简单的正则语法,对于复杂的正则语法网上都能搜到。但无论怎样,前提是要弄清楚正则的属性和方法。


创建正则对象

在AutoCAD中创建正则表达式对象:

  1. (setq RegObj (vlax-create-object "vbscript.regexp"))

对象创建成功时,可以用以下代码检查 RegObj 对象支持的属性和方法:

  1. (vlax-dump-object RegObj t)

返回如下:

  1. ;特性值:
  2. ; Global = 0
  3. ; IgnoreCase = 0
  4. ; Multiline = 0
  5. ; Pattern = ""
  6. ;支持的方法:
  7. ; Execute (1)
  8. ; Replace (2)
  9. ; Test (1)

可以发现,正则对象支持的 4 个属性和 3 个方法,其组织结构图如下:
(yxp_xa)Lisp正则表达式的属性和方法 - 图1


属性

正则表达式支持的属性有 4 个,分别为 Global、IgnoreCase、Multiline、Pattern

Global 全局搜索

默认值为 0,正则引擎默认搜索到第一个关键字后停止;如果需要全局搜索,可将其属性设置为 1,代码如下:

  1. (vlax-put-property RegObj 'Global 1)

IgnoreCase 大小写敏感

默认值为 0,敏感模式,即搜索时区分大小写;如需忽略大小写代码如下:

  1. (vlax-put-property RegObj 'IgnoreCase 1)

Multiline 多段搜索

默认 0,不分段。此参数仅对元字符^和$(开始和结束)有影响
当设置为 1 时,^|$ 代表每行的开始或结束

  1. (vlax-put-property RegObj 'Multiline 1)

Pattern 搜索时的描述字符串

正则表达式的核心参数,正则表达式变化多样的语法靠此参数实现
例如:不含换行符的任意字符

  1. (vlax-put-property RegObj 'Pattern ".")

方法

正则表达式支持的方法有 3个,分别为 ExecuteReplaceTest

Test 方法

测试目标文本中,是否包含正则表达式所描述的字符串(即 Pattern 参数)。

  1. (vlax-invoke RegObj 'Test "abcefg")

返回值: 未找到时返回 0 ; 找到则返回 -1

Replace 方法

在目标文本中用正则表达式查找到的字符串替换,并返回替换结果。
例如用 “=” 替换字符串中的 “c”

  1. (vlax-put-property RegObj 'Pattern "c")
  2. (vlax-invoke RegObj 'Replace "abcefg" "=")

返回 “ab=efg”
变量分组
来看这一段文字:”白菜20萝卜56土豆31茄子47”,我们需要为数字后加一个单位 “kg,”

  1. (vlax-put-property RegObj 'Pattern "\\w+")
  2. (vlax-invoke RegObj 'Replace "白菜20萝卜56土豆31茄子47" "kg,")

返回 “白菜kg,萝卜kg,土豆kg,茄子kg,”
结果把数字也替换掉了,怎么办?我们需要匹配的字符串出现在它原来的地方,实现插入字符串的效果。这时候就需要用到变量的分组,用 “$1” 代表第一组正则 Pattern , Pattern 语法单元需要用 () 分组,每对括号代表1组变量。

  1. (vlax-put-property RegObj 'Pattern "(\\w+)")
  2. (vlax-invoke RegObj 'Replace "白菜20萝卜56土豆31茄子47" "$1kg,")

返回 “白菜20kg,萝卜56kg,土豆31kg,茄子47kg,”
变量分组最多可以支持到 99 组。

Execute 方法

在目标文本中执行正则表达式搜索。 返回一个 Matches 对象集合,该集合具有
count 属性(匹配次数)、 item 属性(项索引),以及一个 matche 对象

  1. (vlax-put-property RegObj 'Pattern "\\w+")
  2. (setq mat (vlax-invoke RegObj 'Execute "我们we你们you这儿here那儿there"))

检查 count 属性

  1. (vlax-get-property mat 'count)

返回 4,即匹配了 4次
检查 item 的第一项

  1. (vla-get-value (vlax-get-property mat 'item 0))

返回第一个匹配的对象 we
如需所有对象的值,可以用 vlax-for 函数遍历 matche 对象集合,该对象具有四个属性,但我们只需要 value 属性。

  1. (setq L nil)
  2. (vlax-for x mat (setq L (cons (vla-get-value x) L)))

返回:(“there” “here” “you” “we”)
举一个简单的栗子

  1. (defun test (s p / L)
  2. (setq r (vlax-create-object "vbscript.regexp"))
  3. (vlax-put-property r 'Global 1)
  4. (vlax-put-property r 'Pattern p)
  5. (vlax-for x (vlax-invoke r 'Execute s)(setq L (cons (vla-get-value x) L)))
  6. (vlax-release-object r)
  7. (reverse L)
  8. )

以下代码实现中英文按字符分离的效果:

  1. (test "我爱CAD" ".")

返回 (“我” “爱” “C” “A” “D”)
如果需要中英文按词组分离,只需要设置不同的 Pattern 属性即可。

  1. (test "我爱CAD你喜欢CAD吗" "([\\u4e00-\\u9fa5])+|([a-zA-Z])+")

返回 (“我爱” “CAD” “你喜欢” “CAD” “吗”)