0

I want to replace the first 104 digits as it follows:

1    -->   a
...
26   -->   z
27   -->   aa
...
52   -->   az
53   -->   ba
...
104  -->   bz

I have tried as it follows:

(defun digits-to-letters ()
  (interactive)

  (goto-char (point-min))

  (save-excursion
    (save-restriction
      (narrow-to-region (search-forward "\\title" nil t)
            (search-forward "\\abstract" nil t))

      (goto-char (point-min))

      (while (search-forward-regexp "\\([0-9]+\\)" nil t)
      (setq digit (match-string 0))

    ;; 1-26 to a-z
    (if (< digit 27)
        (perform-replace digit
                 `((lambda (data count)
                     (string (+ (1- ?a) digit))))
                 t t nil 1 nil (point-min) (point-max))

      ;; 27-52 to aa-az
      (if (and (> digit 26)
           (< digit 53))
           (perform-replace digit
                   `((lambda (data count)
                      (string (+ (1- ?a) (concat "a"
                                                  digit)))))
                   t t nil 1 nil (point-min) (point-max))

        ;; 53-104 to ba-bz
        (if (and (> digit 52)
             (< digit 105))
             (perform-replace "\\([0-9]+\\)"
                 `((lambda (data count)
                     (string (+ (1- ?a) (concat "b"
                                                digit)))))
                 t t nil 1 nil (point-min) (point-max))
          )))
    ))))

It gives me the following error:

Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p #("1" 0 1 (fontified t)))

P.S. I have just asked something like this, but for the first 26 digits: How to replace a digit by a letter?.

Updates

There is a mistake in the correspodence between digits and letters:

53   -->  ba
...
78   -->  bz
79   -->  ca
...
104  -->  cz 

I have corrected my code as it follows:

(defun digits-to-letters ()
  (interactive)

  (goto-char (point-min))

  (save-excursion
    (save-restriction
      (narrow-to-region (search-forward "\\title" nil t)
                (search-forward "\\abstract" nil t))

      (goto-char (point-min))

      (while (search-forward-regexp "\\([0-9]+\\)" nil t)
        (setq digit (string-to-number (match-string 0)))
        (setq sdigit (match-string 0))

        ;; 1-26 to a-z
        (if (< digit 27)
        (replace-match (string (+ (1- ?a) digit)))

          ;; 27-52 to aa-az
          (if (and (> digit 26)
               (< digit 53))
              (replace-match (concat
                              "a"
                              (string (+ (1- ?a) (- digit 26)))))

            ;; 53-78 to ba-bz
            (if (and (> digit 52)
                 (< digit 79))
                 (replace-match (concat
                                 "b"
                                 (string (+ (1- ?a) (- digit 52)))))

              ;; 79-104 to ba-bz
              (if (and (> digit 78)
                   (< digit 105))
                   (replace-match (concat
                                   "c"
                                   (string (+ (1- ?a) (- digit 78)))))

        ))))

    ))))

Now it works.

2
  • 1
    You set digit to (match-string 0) and compare that string in (< digit 27) with a number. Maybe you want to use (setq digit (string-to-number (match-string 0))). Do you really want to use perform-replace? You also use digit later on as string to replace. So you need both the numeric value and the string. Maybe introduce one more variable for that.
    – Tobias
    Commented Feb 11, 2020 at 17:14
  • The error message says that your code expected a number or marker but was passed a (propertized) string with a single character, instead. Chars are the same as integers - it's probably a character that the code expected, and you passed it a string with that char, instead.
    – Drew
    Commented Feb 11, 2020 at 18:56

2 Answers 2

2

104 would be cz I think.

Using org mode eval setup:-- I suspect there are better choices fr functions but I'm an elisp learner.

These conversions might be more appropriates in your code in that there's less if/thens based on ranges.

#+begin_src emacs-lisp

  (setq c 104)
  (setq lsc (char-to-string (+ (% (- c 1) 26) (string-to-char "a"))))
  (setq msc (char-to-string (- (+ (/ (- c 1) 26) (string-to-char "a")) 1)))
  (concat msc lsc)
#+end_src

#+RESULTS:
: cz

Tidy to your desires. I didnt check for <27 so single digit but your framework does.

2

You can use org-number-to-letter from org-table.el (requires at least Emacs 26.1 or Org 9.1.9?)

(require 'org-table)

(org-number-to-letters 26)
;; => "Z"

(org-number-to-letters 52)
;; => "AZ"

And type C-M-% (query-replace-regexp) with

[0-9]+ → \,(org-number-to-letters \#&)

If you need to do the search-and-replace from Lisp, use re-search-forward and replace-match instead, don't use perform-replace:

(while (re-search-forward "[0-9]+" nil t)
  (replace-match
   (org-number-to-letters
    (string-to-number (match-string 0)))))

or replace-regexp-in-string:

(replace-regexp-in-string
 (rx (1+ num))
 (lambda (s)
   (org-number-to-letters
    (string-to-number s)))
 "Hello, 731!")
;; => "Hello, ABC!"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.