明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 710|回复: 7

[讨论] [解决]类array的vla对象怎样取得任意子项而不是枚举

[复制链接]
发表于 2019-5-11 17:21:06 | 显示全部楼层 |阅读模式
本帖最后由 CAD新军 于 2019-5-12 11:39 编辑
  1. _$ (vlax-dump-object matches)
  2. ; IMatches: nil
  3. ;特性值:
  4. ;   Count (RO) = 4
  5. ;   Item (RO) = ...不显示带索引的内容...
  6. ;   _NewEnum (RO) = #<IUnknown 000000004dda9ca0>
  7. T
  8. _$
复制代码
我现在在编的一个小脚本,大量代码需要用到正则表达式,网上找了几个vbs实现的,用着都发现有些小问题,想改进一下时,第一次碰vlax对象,遇到了问题.

一个正则返回对象 matches在VBS中时这样一个Array : [ Matches(0) Matches(1) .... Matches (n) ]
而每个Matches(n) 也是一个Array ,形如 [ FirstIndex Value Submatches ]

VBS里面就直接 Matches(3) 就能取到第4个。而我找到的函数都是用 (vlax-for m matches (vlax-get m 'Value)) 来取得各个值的,我想问有没有类似(nth n list)的方法,直接取得某个Array里面的值呢?

我其实用的是Submatches数组里面的值,但问题是 vlax-for 遍历 submatches时,遇到空的数组会直接出错终止循环。比如这个正则表达式:
(1)(a)?(2)?
当匹配 1a2时, 三个捕获都会得到, 1,a,2
但匹配 12时,因为第二个捕获没有命中,只会返回 1,而无视后面的捕获,这就出问题了



精简出来的复现代码:
  1. (defun RegExpSet (pattern / regex)
  2.   (setq regex   (vlax-create-object "VBScript.RegExp")  )
  3.     (vlax-put regex 'Pattern pattern)
  4.     (vlax-put regex 'IgnoreCase acTrue)
  5.     (vlax-put regex 'Global acTrue)
  6.   regex
  7. )

  8. (setq slist nil
  9.          str "13"); ############这里改成"1a3"就会正常不出错误
  10. (setq ms (vlax-invoke (RegExpSet "([0-9])([abc])?([0-9])?" ) 'Execute str))
  11. (vlax-for m ms (setq jj m))
  12. ; 这句其实就是标题的问题,我只想要ms(0),因为不会直接读取 ms(0)只好用vlax-for
  13. ;这里组里只有一个值,用vlax-for的办法读出来,记成 jj, 现在jj 相当于 Matches(0)
  14. (setq sub (vlax-get jj 'SubMatches))
  15. ; sub 就相当于 Matches(0).SubMatches, 这也是一个Array,包含所有捕获字符串分组
  16. (vlax-for s sub (setq slist (cons s slist)))
  17. ; 获得每个submatches的值,合并到slist 表中
  18. ;同理这也是标题中的问题,我只想要某一段捕获比如submatches(2),但又只好用vlax-for

  19. ;;直接粘贴的话,运行到上面一句会出错...str改成1a3就能整体完成

  20. (princ slist);可以看到用"13"去匹配,会先是1然后就没有了,如果用"1a3"去匹配会正确返回1 a 3
  21. (vlax-dump-object sub);这里就是开头的情况了




发表于 2019-5-12 09:41:31 | 显示全部楼层
(vlax-dump-object sub) 获取的是属性列表,不含有方法,当然这个对象本身也没有方法。
  1. _1$ (vlax-dump-object sub t)
  2. ; ISubMatches: nil
  3. ; Property values:
  4. ;   Count (RO) = 3
  5. ;   Item (RO) = ...Indexed contents not shown...
  6. ;   _NewEnum (RO) = #<IUnknown 000001338f19d790>
  7. ; No methods
  8. T

访问对象的属性用(vlax-get-property object property)那我们来试试是否可行
  1. _$ (vlax-get-property sub 'item)
  2. ; error: too few actual parameters
  3. _1$

发现返回错误,提示参数太少,根据改对象的属性,有一个count数量,而item属性提示了Indexed ,那么我们来猜测是否是增加一个序号
  1. _1$ (vlax-get-property sub 'item 0)
  2. #<variant 8 1>
  3. _1$

看来返回是成功的,接着尝试获取这个变体的值。
  1. _1$ (vlax-variant-value (vlax-get-property sub 'item 0))
  2. "1"

我们可以依次获取后面的序号的值。
  1. _1$ (vlax-variant-value (vlax-get-property sub 'item 1))
  2. nil
  3. _1$ (vlax-variant-value (vlax-get-property sub 'item 2))
  4. "3"



回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2019-5-11 19:07:57 | 显示全部楼层
vlax-for的问题我已经解决了,找到一个不会跳出循环的方法。标题的问题,就是vla数组对象怎么直接选第n个元素还没有方法
 楼主| 发表于 2019-5-12 02:58:47 | 显示全部楼层
晓东也发了,里面提到(vla-item 的方法,搜索了一下好像确实是这个用途的,无奈对正则的返回对象好像无法操作?或者我用的不对
发表于 2019-5-12 09:50:36 | 显示全部楼层
前面的ms变量也可以用同样的方式查询以及猜测。
  1. _$ (vlax-dump-object ms t)
  2. ; IMatchCollection2: nil
  3. ; Property values:
  4. ;   Count (RO) = 1
  5. ;   Item (RO) = ...Indexed contents not shown...
  6. ;   _NewEnum (RO) = #<IUnknown 000001338f19d370>
  7. ; No methods
  8. T

返回属性数量1,有item属性。那么同理试试。。
  1. _1$ (vlax-get-property ms 'item 0)
  2. #<VLA-OBJECT IMatch2 000001338c09ad80>
  3. _1$

提示返回vla-object对象,所以对象可以直接使用了,无需vlax-for,vlax-for是对集合遍历,应该没有办法退出,等同于lisp中的repeat。
 楼主| 发表于 2019-5-12 11:37:17 | 显示全部楼层
本帖最后由 CAD新军 于 2019-5-12 11:42 编辑
edata 发表于 2019-5-12 09:50
前面的ms变量也可以用同样的方式查询以及猜测。

返回属性数量1,有item属性。那么同理试试。。

感谢啊。我怕没人回答还卖了个关子的。

上面说vlax-for遇到未定义对象时会出错跳出应该是cad的bug了,但在autodesk的开发资料里面发现一个方法,
vlax-map-collection,这个方法遇到未定义对象返回的是nil,可以继续循环的,改进的正则表达式如下


  1. ;; RegExpSet
  2. ;; Returns the current VBScript.RegExp instance after defining its properties.
  3. ;;
  4. ;; Arguments
  5. ;; pattern    : Pattern to search.
  6. ;; ignoreCase : If non nil, the search is done ignoring the case.
  7. ;; global     : If non nil, search all occurences of the pattern;
  8. ;;              if nil, only searches the first occurence.

  9. (defun RegExpSet (pattern ignoreCase global / regex)
  10.   (setq regex
  11.          (cond
  12.            ((vl-bb-ref '*regexp*))
  13.            ((vl-bb-set '*regexp* (vlax-create-object "VBScript.RegExp")))
  14.          )
  15.   )
  16.   (vlax-put regex 'Pattern pattern)
  17.   (if ignoreCase
  18.     (vlax-put regex 'IgnoreCase acTrue)
  19.     (vlax-put regex 'IgnoreCase acFalse)
  20.   )
  21.   (if global
  22.     (vlax-put regex 'Global acTrue)
  23.     (vlax-put regex 'Global acFalse)
  24.   )
  25.   regex
  26. )


  27. ;; RegExpExecute
  28. ;; Returns the list of matches with the pattern found in the string.
  29. ;; Each match is returned as a sub-list containing:
  30. ;; - the match value
  31. ;; - the index of the first character (0 based)
  32. ;; - a list of sub-groups.
  33. ;;
  34. ;; Arguments
  35. ;; string     : String in which the pattern is searched.
  36. ;; pattern    : Pattern to search.
  37. ;; ignoreCase : If non nil, the search is done ignoring the case.
  38. ;; global     : If non nil, search all occurences of the pattern;
  39. ;;              if nil, only searches the first occurence.

  40. ;;
  41. ;; Examples
  42. ;; (RegExpExecute "foo bar baz" "ba" nil nil)               ; => (("ba" 4 nil))
  43. ;; (RegexpExecute "12B 4bis" "([0-9]+)([A-Z]+)" T T)        ; => (("12B" 0 ("12" "B")) ("4bis" 4 ("4" "bis")))
  44. ;; (RegexpExecute "-12 25.4" "(-?\\d+(?:\\.\\d+)?)" nil T)  ; => (("-12" 0 ("-12")) ("25.4" 4 ("25.4")))
  45. (defun RegExpExecute2 (string pattern ignoreCase global / sublst lst)
  46.   (vlax-for match (vlax-invoke (RegExpSet pattern ignoreCase global) 'Execute string)
  47.     (setq sublst nil)
  48.     (vl-catch-all-apply
  49.       '(lambda ()
  50.          (vlax-map-collection  (vlax-get match 'SubMatches)
  51.            ;(if submatch
  52.            ;  (setq sublst (cons submatch sublst))
  53.            ;)
  54.            '(lambda(str)(setq sublst (cons str sublst)))
  55.          )
  56.        )
  57.     )
  58.     (setq lst (cons (list (vlax-get match 'Value)
  59.                           (vlax-get match 'FirstIndex)
  60.                           (reverse sublst)
  61.                     )
  62.                     lst
  63.               )
  64.     )
  65.   )
  66.   (reverse lst)
  67. )

由于我的用途需要,要借助每一个捕获字符串定位,所以输出所有捕获串,无论是否有捕获(这也符合其它正则语言的返回结果)
  1. (regexpexecute2 "1a3" "(1)?(a)?(3)?" nil nil)
  2. ;返回 ("1a3" 0 ("1" "a" "3"))
  3. (regexpexecute2 "13" "(1)?(a)?(3)?" nil nil)
  4. ;返回 ("13" 0 ("1" nil "3"))
复制代码
 楼主| 发表于 2019-5-12 11:59:17 | 显示全部楼层
edata 发表于 2019-5-12 09:50
前面的ms变量也可以用同样的方式查询以及猜测。

返回属性数量1,有item属性。那么同理试试。。

另外前辈我想请教一下,你的CAD是英文版吗?我的vlisp控制台出来的也有一些汉化了,让我很难借助谷歌搜索英文结果,比如 ...不显示带索引的内容... ...Indexed contents not shown...换成英文我能看懂,但写成中文要搜索英文结果就难了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-25 19:45 , Processed in 0.184481 second(s), 25 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表