Is there a way to intern a keyword from a string without getting the
'|' characters?
CL-USER> (intern "abc" :keyword)
:|abc|
:EXTERNAL
whereas
CL-USER> (intern (format nil "~a" :abc) :keyword)
:ABC
:EXTERNAL
I'm trying to mix the two:
CL-USER> (intern (format nil "~a-~a" "key" :abc) :keyword)
:|key-ABC|
:EXTERNAL
--jeff
On 8 Sep 2005 08:41:44 -0700, "Jeff" <····················@boeing.com>
wrote:
>Is there a way to intern a keyword from a string without getting the
>'|' characters?
:|abc| is the symbol in the keyword package whose
characters are lowercase a b c. (See below)
The '|' characters aren't "really" there. They are just printed by
the printer so that the symbol, whose characters are lowercase a b c,
can be reread, and so that you, the reader, know that the characters
are lowercase.
See the discussion of the printer and the reader and standard case
conversion in the Hyperspec.
>
>CL-USER> (intern "abc" :keyword)
>:|abc|
>:EXTERNAL
(intern (string-upcase "abc") :keyword)
>
>whereas
>
>CL-USER> (intern (format nil "~a" :abc) :keyword)
>:ABC
>:EXTERNAL
Because :abc is really the symbol whose characters are uppercase A B C
>
>I'm trying to mix the two:
>
>CL-USER> (intern (format nil "~a-~a" "key" :abc) :keyword)
>:|key-ABC|
>:EXTERNAL
>
>--jeff
"Jeff" <····················@boeing.com> writes:
> I'm trying to mix the two:
>
> CL-USER> (intern (format nil "~a-~a" "key" :abc) :keyword)
> :|key-ABC|
> :EXTERNAL
At the risk of getting in trouble for not properly handling situations
where someone sets READTABLE-CASE to something other than UPCASE, you
can do the following:
(intern (format nil ··@:(~a-~a~)" "key" :abc) :keyword)
which you can nicely generalize via format hackery to
(defun create-keyword (&rest components)
(intern (format nil ··@:(~{~a~^-~}~)" components) :keyword))
If you want to have a simple solution that respects READTABLE-CASE
settings, then you can always use READ-FROM-STRING instead of INTERN:
(read-from-string (format nil "~a-~a" "key" :abc) :keyword)
but this then opens other cans of worms with regard to inputs that need
escaping to be symbol constituents, worrying about the setting of
*READ-EVAL*, etc.
That leaves writing your own handler for the current state of
READTABLE-CASE. But this brings up a missing built-in function in
Common Lisp. There is no standard function to do the STRING-INVERT
operation from the reader. It is something that you will need to write
on your own.
(defun frob-symbol-name-according-to-readcase (name)
(case (readtable-case *readtable*)
(:upcase (upcase-string name))
(:downcase (downcase-string name))
(:preserve name)
(:invert (if (some #'upper-case-p name)
(if (some #'lower-case-p name)
name ; Mixed case => preserve
(string-downcase name)) ; No lower case letters
(string-upcase name))))) ; No upper case letters
I think I got the :invert case correct....
You can then call (intern (frob-symbol-name-according-to-readcase name) :keyword)
and get the behavior you are seeking.
--
Thomas A. Russ, USC/Information Sciences Institute
Jeff wrote:
> Is there a way to intern a keyword from a string without getting the
> '|' characters?
>
> CL-USER> (intern "abc" :keyword)
> :|abc|
> :EXTERNAL
Easy:
CL-USER> (intern "ABC" :keyword)
:ABC
HTH,
Patrick
Jeff asks
> Is there a way to intern a keyword from a string without getting the
> '|' characters?
>
> CL-USER> (intern "abc" :keyword)
> :|abc|
> :EXTERNAL
The secret is in the print-escape. Try
(let ((key (intern "abc" :keyword)))
(dolist (flag '(t nil) (symbol-name key))
(write key :escape flag)
(terpri)))
:|abc|
abc
"abc"
You are creating a symbol whose name is the three lower case
characters a,b,c.
The vertical lines are escape characters put there by the
printer in anticipation of you trying to read the character
back in using the current readtable.
Try
* (setf (readtable-case *readtable*) :preserve)
* (INTERN "abc" :KEYWORD)
:abc
:EXTERNAL
The vertical lines have gone, because they were in a sense,
never there. Since the readtable at the time of printing
preserves case, the printer in the ReadEvalPrintLoop is
happy to write out the symbol name without escape characters
to protect it from being upcased when it is read back in.
Alan Crowe
Edinburgh
Scotland
PS you will need (SETF (READTABLE-CASE *READTABLE*) :UPCASE)
to get back to normal.
Thank you all for the explanations. It all makes sense now. The case
preservation technique is well worth knowing. In the case at hand
there's no requirement for lower case, so I'll probably just change it
to upper.
-jeff
"joesb" <··········@gmail.com> writes:
> Regarding case sensitive lisp, How would this work out?
Common Lisp is already case sensitive. (That's in fact the issue here:
the symbol whose name is "abc" is different than the symbol whose name
is "ABC".) However--and this is the bit that causes folks to
misidentify Lisp as case insensitive--the reader (in the default
setting) smashes the case of unescaped letters in symbols to upper
case. I.e. it's not that the reader ignores differences in case (which
would be case-insensitive) but that it normalizes symbol names to a
particular case (upper).
-Peter
--
Peter Seibel * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/