Emacs Lisp
Предварительные сведения
Здесь мы будем использовать функции из dash
и s
сторонних библиотек, которые выможно установить в Emacs из MELPA, используя систему пакетов Emacs. Как установить пакеты в Emacs .dash
- это библиотека управления списками и деревьями, которая также содержит различные функции, которые делают код более кратким и функциональным .s
- библиотека для работы со строками.Когда вы часто пишете код в Elisp, я настоятельно рекомендую установить эти пакеты, чтобы упростить кодирование.
-map
- это то же самое, что и mapcar
, он просматривает список, вызывает функциюдля каждого элемента и возвращает список со всеми измененными элементами.Например, (-map '1+ '(1 2 3)) ; returns (2 3 4)
.Однако -map
имеет версию анафорического макроса , которая позволяет писать краткий код вместо передачи лямбда-выражений.Анафорические версии начинаются с 2 тире.Например, (--map (+ 10 it) '(1 2 3))
эквивалентно (-map (lambda (x) (+ 10 x)) '(1 2 3))
.
->>
- это макрос потоков из dash
, который похож на состав функции , но в обратном порядке,Например, (number-to-string (-sum (-map '1+ '(1 2 3))))
, который возвращает "9"
, эквивалентен (->> '(1 2 3) (-map '1+) -sum number-to-string)
.
Строковый подход
Предположим, что вся ваша структура хранится в строке s
.Затем вы должны найти каждое вхождение последовательности символов вида #[some_number]
, используя, возможно, регулярное выражение, и заменить его на число, увеличенное на 11.
(let* ((old (-map 'car (s-match-strings-all "#[0-9]\\{1,3\\}" s)))
(new (--map (->> it
(s-chop-prefix "#")
string-to-number
(+ 11)
number-to-string
(s-prepend "#"))
old)))
(s-replace-all (-zip old new) s))
Подход дерева
Но подождитево-вторых, ваша структура рекурсивно заключена в скобки, это s-выражение !Мы можем пройти его как дерево и заменить каждое вхождение строки, начинающейся с # и содержащей числовое значение, новым значением, увеличенным на 11. -tree-map-nodes
похоже на -map
для деревьев.Функция применяется только тогда, когда предикат возвращает true.IOW, он пропускает некоторые элементы без изменений, если предикат для них не выполняется.
-tree-map-nodes
повторяется двумя способами, как по ширине, так и по глубине.Это означает, что он обрабатывает списки как обычные элементы, а первый элемент - весь список.Например, (-tree-map-nodes 'zerop '1+ '(0 (1 (0) 1) 0))
не правильно, он выдаст эту ошибку: *** Eval error *** Wrong type argument: numberp, (0 (1 (0) 1) 0)
.Вместо этого вы должны сначала проверить, является ли элемент числом.Например, (--tree-map-nodes (and (numberp it) (zerop it)) (1+ it) '(0 (1 (0) 1) 0))
вернется (1 (1 (1) 1) 1)
.Предположим, ваше дерево находится в переменной q
.Тогда решение будет ниже, и оно вернет новое модифицированное s-выражение:
(--tree-map-nodes (and (stringp it)
(eq (elt it 0) ?#)
(s-numeric? (s-chop-prefix "#" it)))
(->> it
(s-chop-prefix "#")
string-to-number
(+ 11)
number-to-string
(s-prepend "#"))
q)