0

In a related thread https://emacs.stackexchange.com/a/34336/2287, a string (containing JSON data) is converted using json-read-from-string. The value returned in that example looks like this:

    ((1 . [((id . 2)
            (attribute . salutation)
            (displayName . Salutation)
            (category . 1))
           ((id . 4)
            (attribute . middlename)
            (displayName . Middle Name)
            (category . 1))
           ((id . 6)
            (attribute . suffix)
            (displayName . Suffix)
            (category . 1))
           ((id . 8)
            (attribute . city)
            (displayName . City)
            (category . 1))
           ((id . 9)
            (attribute . state)
            (displayName . State)
            (category . 1))
           ((id . 11)
            (attribute . email)
            (displayName . Email)
            (category . 1))
           ((id . 12)
            (attribute . telephone)
            (displayName . Telephone)
            (category . 1))
           ((id . 10)
            (attribute . zipCode)
            (displayName . Zip Code)
            (category . 1))
           ((id . 13)
            (attribute . telephoneExtension)
            (displayName . Telephone Extension)
            (category . 1))
           ((id . 7)
            (attribute . streetAddress)
            (displayName . Street Address)
            (category . 1))
           ((id . 3)
            (attribute . firstName)
            (displayName . First Name)
            (category . 1))
           ((id . 1)
            (attribute . fullName)
            (displayName . Full Name)
            (category . 1))
           ((id . 5)
            (attribute . lastName)
            (displayName . Last Name)
            (category . 1))
           ((id . 14)
            (attribute . notes)
            (displayName . Notes)
            (category . 1))])
     (2 . [((id . 15)
            (attribute . name)
            (displayName . Name)
            (category . 2))
           ((id . 16)
            (attribute . address)
            (displayName . Address)
            (category . 2))
           ((id . 17)
            (attribute . phone)
            (displayName . Phone)
            (category . 2))
           ((id . 18)
            (attribute . email)
            (displayName . email)
            (category . 2))
           ((id . 19)
            (attribute . url)
            (displayName . URL)
            (category . 2))])
    (3 . [((id . 20)
           (attribute . name)
           (displayName . Name)
           (category . 3))
          ((id . 21)
           (attribute . address)
           (displayName . address)
           (category . 3))
          ((id . 22)
           (attribute . county)
           (displayName . County)
           (category . 3))
          ((id . 23)
           (attribute . state)
           (displayName . State)
           (category . 3))
          ((id . 24)
           (attribute . zipcode)
           (displayName . Zip Code)
           (category . 3))
          ((id . 25)
           (attribute . pin)
           (displayName . PIN)
           (category . 3))
          ((id . 26)
           (attribute . longitude)
           (displayName . Longitude)
           (category . 3))
          ((id . 27)
           (attribute . latitude)
           (displayName . Latitude)
           (category . 3))]))

Evaluating the above-mentioned return value with (assoc '\1 ...) produces a cell, the car of which is a symbol whose name is the string "1". The O.P. in that related thread (like myself) experiences difficulty printing the symbol using message [(void-function \,)], and in the comments a solution to accomplish that objective is to use setq: (setq id '\1).

I would like to convert the symbol 1 to a number without using a global variable. I have tried storing that symbol as a let-bound variable and then attempted to change it with setq, however, this does not work (presumably because the variable is only let-bound).


EDIT: To include a minimal working example below:

EXAMPLE:

(let* ((string
"{
  \"access_token\" : \"1234\",
  \"scope\" : \"PlaceTrades AccountAccess MoveMoney\",
  \"expires_in\" : 1800,
  \"token_type\" : \"Bearer\"
}")
       (json (progn (require 'json)
                    (json-read-from-string string)))
       (token-type (cdr (assq 'token_type json)))
       (expires-in (cdr (assq 'expires_in json)))
       (scope (cdr (assq 'scope json)))
       (access-token (cdr (assq 'access_token json))))
  (message "token-type: %s\nexpires-in: %s\nscope: %s\naccess-token: %s"
           token-type, expires_in, scope, access-token)
  access-token)

DEBUGGER:

Debugger entered--Lisp error: (void-function \,)
  ,expires_in
  (message "token-type: %s\nexpires-in: %s\nscope: %s\naccess-tok..." token-type ,expires_in ,scope ,access-token)
  (let* ((string "{\n  \"access_token\" : \"1234\",\n  \"scope\" : \"PlaceTra...") (json (progn (require 'json) (json-read-from-string string))) (token-type (cdr (assq 'token_type json))) (expires-in (cdr (assq 'expires_in json))) (scope (cdr (assq 'scope json))) (access-token (cdr (assq 'access_token json)))) (message "token-type: %s\nexpires-in: %s\nscope: %s\naccess-tok..." token-type ,expires_in ,scope ,access-token) access-token)
  (progn (let* ((string "{\n  \"access_token\" : \"1234\",\n  \"scope\" : \"PlaceTra...") (json (progn (require 'json) (json-read-from-string string))) (token-type (cdr (assq 'token_type json))) (expires-in (cdr (assq 'expires_in json))) (scope (cdr (assq 'scope json))) (access-token (cdr (assq 'access_token json)))) (message "token-type: %s\nexpires-in: %s\nscope: %s\naccess-tok..." token-type ,expires_in ,scope ,access-token) access-token))
  eval((progn (let* ((string "{\n  \"access_token\" : \"1234\",\n  \"scope\" : \"PlaceTra...") (json (progn (require 'json) (json-read-from-string string))) (token-type (cdr (assq 'token_type json))) (expires-in (cdr (assq 'expires_in json))) (scope (cdr (assq 'scope json))) (access-token (cdr (assq 'access_token json)))) (message "token-type: %s\nexpires-in: %s\nscope: %s\naccess-tok..." token-type ,expires_in ,scope ,access-token) access-token)) t)
  elisp--eval-last-sexp(nil)
  eval-last-sexp(nil)
  funcall-interactively(eval-last-sexp nil)
  call-interactively(eval-last-sexp nil nil)
  command-execute(eval-last-sexp)
Drew
  • 75,699
  • 9
  • 109
  • 225
lawlist
  • 18,826
  • 5
  • 37
  • 118
  • What does the JSON string look like? The return value you've posted does not seem to be a legal elisp object. – NickD Dec 27 '21 at 21:13
  • ... and when I try to apply `json-read-from-string` to the JSON string from the linked question, I get: `Debugger entered--Lisp error: (json-object-format "," 0) signal(json-object-format ("," 0)) json-read-object() json-read()...`. – NickD Dec 27 '21 at 21:25
  • I corrected your question. There is no backslash in the symbol name. The symbol name is a numeric string (a numeral), such as `"1"`. – Drew Dec 27 '21 at 21:40
  • Thank you -- I edited the question to include a minimal working example underneath the original question. – lawlist Dec 27 '21 at 22:20
  • I didn't notice @phils's answer. I checked your "minimal working example" and noticed the same thing he did. Went to write it up and saw he already had. Keith, I think you should have been able to figure this one out. ;-) That's what comes from mixing languages - comma-vs-space separators and hyphen-vs-underscore separators. – Drew Dec 28 '21 at 03:26
  • @Drew -- I think it's because I spent the whole long weekend learning a little bit of Python, and today I assumed the Lisp error had to have been something super complex beyond my current level of understanding ... It could also be lack of sleep ... Although the question will not help other forum participants in the future, it sure helped me a lot when reducing the issue down to a minimal working example so that `phils` could resolve the problem. In hindsight, I felt pretty foolish for wasting everyone's time/effort. Sorry .. and thank you so much for all of your help these many years! – lawlist Dec 28 '21 at 03:44
  • No, you didn't waste anyone's time. And there's no reason to feel foolish. I'm guessing you learned something about debugging (more divide & conquer). Even your "minimal example" can be simplified, and doing that would have answered your question for you. E.g., removing some of the irrelevant variables, you would have simplified the `message` call, discovering the comma problem. And then you might have seen the incorrect variable name. – Drew Dec 28 '21 at 04:54

3 Answers3

2

You can get the symbol name with symbol-name, which returns a string, and then convert the string to a number:

(string-to-number (symbol-name '\1))
==> 1
NickD
  • 27,023
  • 3
  • 23
  • 42
  • Thank you for idea ... In this particular context, however, I get: `(wrong-type-argument symbolp 1)` – lawlist Dec 27 '21 at 21:00
  • I'm not sure what context you are talking about: if you evaluate the expression in my answer, do you not get the number 1? If that's not what you meant, then showing what expression generated the error message would help. – NickD Dec 27 '21 at 21:03
  • FWIW, I get 0, not 1, when I evaluate your sexp. The `symbol-name` sexp itself returns the string "`1". If I remove your backquote then I get 1. – Drew Dec 27 '21 at 21:14
  • Ugh, typo: there should be no backquote. – NickD Dec 27 '21 at 21:18
  • Thank you @NickD -- I edited the question to include a minimal working example underneath the original question. – lawlist Dec 27 '21 at 22:20
2

I probably don't understand your problem. Your question isn't very clear (what calls to message are you using?).

But if I do understand what you're trying to do, it pretty much amounts to this: You have symbols whose names are numeric strings. E.g. the symbol 1 has name "1". (In Lisp, you can refer to such a symbol literally, using \1, but the backslash is not part of the name.)

(setq foo '((\1 . one) (\2 . two)))

(message "FOO: %S" foo)
(message "FOO: %s" foo)

Neither call to message is a problem. They show this, respectively:

FOO: ((\1 . one) (\2 . two))
FOO: ((1 . one) (2 . two))

If I understand correctly, the second is what you want: to see numbers, not symbols whose names are numeric strings.

And there's no need for any variable, such as foo:

(message "%s" '((\1 . one) (\2 . two)))
Drew
  • 75,699
  • 9
  • 109
  • 225
  • Thank you @Drew -- I edited the question to include a minimal working example underneath the original question. – lawlist Dec 27 '21 at 22:21
  • And ... the goal is to not use a *global* variable, if possible. I.e., only using let-bound variables ... – lawlist Dec 27 '21 at 22:25
1
(message "token-type: %s\nexpires-in: %s\nscope: %s\naccess-token: %s"
         token-type, expires_in, scope, access-token)

You've accidentally added commas as list separators.

As the backtrace shows, the error is because of that:

Debugger entered--Lisp error: (void-function \,)
  ,expires_in
  (message "token-type: %s\nexpires-in: %s\nscope: %s\naccess-tok..."
            token-type ,expires_in ,scope ,access-token)
                       ^^^^^^^^^^^

The commas will be treated as attempts to unquote list elements, as if it were a backquoted list. In that syntax the comma needn't be attached to the form in question; it just says "evaluate the following form" so there can be intervening whitespace. The spacing is then being adjusted to the normal formatting when the debugger prints it back to you; hence token-type, expires_in becoming token-type ,expires_in.

The error is (void-function \,) because the reader internally converts this syntax to (\, expires_in), but as the list was not backquoted it never gets processed in the way that the reader expected it to, and winds up being evaluated as a function call.

(read ",foo")
=> (\, foo)

(read ", foo")
=> (\, foo)
phils
  • 48,657
  • 3
  • 76
  • 115