|Function Syntax||(LM:escapewildcards <str>)|
|str||String||String for which to escape wildcard characters|
|String||Supplied string with wildcard characters escaped.|
Introduction & Motivation
Wildcard characters are usually associated with the wcmatch function, where such characters as #, @, ., *, ?, etc. inherit a different meaning than just standard ASCII characters taken at face value.
For example, in a wcmatch expression, an asterisk (*) appearing in the pattern argument will become a wildcard special character which may be used to match any character sequence, (including an empty one), anywhere in the supplied string.
However, other functions also utilise wildcards for pattern matching in strings, one of which is the ssget function. DXF Group codes with string values in the filter list argument of an ssget expression can use wildcards to filter entities with the same DXF group code whose associated string value matches the wildcard pattern.
However, this wildcard property of certain characters can be undesired in some situations.
Consider, for example, the following simple function which will prompt the user for a string, then select all Text objects whose content is equal to the entered string:
(defun c:findtext ( / str ) (if (/= "" (setq str (getstring t "\nSpecify string to find: "))) (sssetfirst nil (ssget "_X" (list '(0 . "TEXT") (cons 1 str) ) ) ) ) (princ) )
At first glance, this program looks like it should do what it says on the tin: find any text that matches the entered string; however, due to the wildcard property of certain characters, it can produce some undesired results.
For example, say the user enters the string: "a,b,c". The above function will select all Text objects whose string equals "a,b,c", but also all Text objects whose string equals "a", "b" or "c" since the comma is a wildcard special character which may be used to separate two or more wildcard patterns.
This is where the wildcard escape character (`), the reverse quote, is introduced. This character will mark the next character in the string as a literal character, to be interpreted at face value.
This function will escape wildcard characters found in a supplied string, ensuring such characters are interpreted literally.
The function will iterate over all characters in the string, ensuring those characters with an alternative wildcard property are prefixed with the wildcard escape character, the reverse quote (`).
Incorporating this function in the above example program results in the following code:
(defun c:findtext ( / str ) (if (/= "" (setq str (getstring t "\nSpecify String to Find: "))) (sssetfirst nil (ssget "_X" (list '(0 . "TEXT") (cons 1 (LM:escapewildcards str)) ) ) ) ) (princ) )
Should the user now enter the string: "a,b,c" when prompted using the above program, we can be sure that only strings whose content matches "a,b,c" will be selected.
;; Escape Wildcards - Lee Mac ;; Escapes wildcard special characters in a supplied string (defun LM:escapewildcards ( str ) (vl-list->string (apply 'append (mapcar '(lambda ( c ) (if (member c '(35 64 46 42 63 126 91 93 45 44)) (list 96 c) (list c) ) ) (vl-string->list str) ) ) ) )
This recursive variant is far slower than the above iterative version (about four times slower in fact for a reasonably long string); however, I have included it as an example of how to solve the problem recursively and using pure Vanilla AutoLISP.
;; Escape Wildcards - Lee Mac ;; Escapes wildcard special characters in a supplied string (defun LM:escapewildcards ( str ) (if (wcmatch str "*[-#@.*?~`[`,]*,*`]*") (if (wcmatch str "[-#@.*?~`[`,]*,`]*") (strcat "`" (substr str 1 1) (LM:escapewildcards (substr str 2))) (strcat (substr str 1 1) (LM:escapewildcards (substr str 2))) ) str ) )
Example Function Call
_$ (LM:escapewildcards "a,b,c") "a`,b`,c" _$ (LM:escapewildcards "1.2") "1`.2"