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.

Onner Irotsab
  • 431
  • 2
  • 9
  • 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 Feb 11 '20 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 Feb 11 '20 at 18:56

2 Answers2

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.

RichieHH
  • 848
  • 4
  • 9
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!"
xuchunyang
  • 14,302
  • 1
  • 18
  • 39