regular-expressions – reemplazar expresiones regulares con consultas y funciones en coincidencia

Pregunta:

EDITAR: dio más contexto para mi primer enfoque.

Mi objetivo es buscar en mis notas cadenas de la forma "4/1/2014" a marcas de tiempo en modo org "<2014-04-01 Wed>" (ese día de la semana en particular puede ser incorrecto). También quiero que las consultas estén activadas para no hacer cosas como reemplazar parte de una URL de esta manera por accidente.

Suponiendo que ya escribí una función de Día de la semana (las quejas son bienvenidas, aunque no forman parte de la pregunta principal):

(defun dow (year month day)
  (interactive)
  (let ((encoded-time (encode-time 1 1 10 day month year)))
    (nth (nth 6 (decode-time encoded-time))
     '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun"))))

Parece que no puedo hacer el resto. Aquí están mis intentos y cuando se quedan cortos:

  1. Primero, intenté usar query-replace-regexp :
(defun date-replace ()
  (interactive)
  (goto-char 1)
  (query-replace-regexp "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]\\{4\\}\\)"
            "<\\3-\\1-\\2 \\,(dow (string-to-number \\3) (string-to-number \\1) (string-to-number \\2))>"))

Recibo un error de "uso no válido de '\' en el texto de reemplazo" y no sé qué hacer con eso incluso después de buscar en Google; parece que la causa más probable es escapar de algo en la cadena de reemplazo que NO es '\', pero no hago nada de eso.

Por cierto, haciendo

M-x query-replace-regexp RET \([0-9]+\)/\([0-9]+\)/\([0-9]\{4\}\) RET <\3-\1-\2 \,(dow (string-to-number \3) (string-to-number \1) (string-to-number \2))> RET

funciona, por eso pensé que todo lo que tenía que hacer era escapar de las barras invertidas.

(otro problema con este enfoque es que no rellena con 0 números de 1 dígito de una manera que me parece limpia, incluso si todo lo demás funcionara)

  1. Luego, intenté usar search-forward-regexp . Aquí hay una solución torpe que funciona (reemplazando la parte relevante del código anterior):
(while (search-forward-regexp "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]\\{4\\}\\)" nil t)
  (let* ((ynum (string-to-number (match-string 3)))
       (mnum (string-to-number (match-string 1)))
       (dnum (string-to-number (match-string 2)))
       (dowstr (dow ynum mnum dnum)))
    (replace-match (format "<%04d-%02d-%02d %s>" ynum mnum dnum dowstr) t nil)))

El único problema aquí es que no consulta y no parece haber indicadores que me permitan hacer eso.

  1. Mi último intento es buscar query-replace y el manual que sugiere usar perform-replace . Así que aquí tengo:
  (perform-replace "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]\\{4\\}\\)"
           ((lambda (data numreps)
              (format "<%04d-%02d-%02d %s>" (nth 1 data) (nth 2 data) (nth 3 data)
                  (dow (nth 1 data) (nth 2 data) (nth 3 data))))
            .
            ((string-to-number (match-string 3))
             (string-to-number (match-string 1))
             (string-to-number (match-string 2))))
           t t t)

y obtengo "Argumento de tipo incorrecto: stringp, nil" que no puedo descifrar.

Si bien mi objetivo inmediato es averiguar qué tipo de solución es la forma correcta de proceder y hacer que funcione, en general estoy más interesado en por qué ocurren estos errores y cómo mejorar la depuración, ya que soy nuevo en el aprendizaje de elisp. ¡Gracias!

Respuesta:

Puede escribir la versión de perform-replace así:

(perform-replace
 "\\b\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]\\{4\\}\\)\\b"
 (cons (lambda (&rest _)
         (let ((data (list (string-to-number (match-string 1))
                           (string-to-number (match-string 2))
                           (string-to-number (match-string 3)))))
           (format "<%04d-%02d-%02d %s>"
                   (nth 2 data) (nth 1 data) (nth 0 data)
                   (dow (nth 0 data) (nth 1 data) (nth 2 data)))))
       nil)
 t t nil)

Experimentalmente, el argumento DELIMITADO no se comporta como esperaba. Establecí ese valor nil y usé \b explícitamente en la expresión regular. Estoy seguro de que hay una razón para eso. (Potencialmente, cuando dice "rodeado por límites de palabras" también significa "y contiene solo una palabra", en cuyo caso el problema sería / ejemplares).


La razón por la que falló su intento de query-replace-regexp fue que esperaba que sus argumentos tuvieran exactamente el mismo aspecto cuando los ingresa de forma interactiva; pero, de hecho, la especificación interactive de ese comando manipula lo que ingresa en el formato que realmente requiere.

Después de ejecutar el comando interactivo, puede usar repeat-complex-command para aprender lo que realmente hizo:

Cx M-: runs the command repeat-complex-command (found in global-map), which is an interactive compiled Lisp function in 'simple.el'. It is bound to <again>, <redo>, Cx M-:, Cx M-ESC.
(query-replace-regexp
 "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]\\{4\\}\\)"
 (quote (replace-eval-replacement
         concat "<\\3-\\1-\\2 "
         (replace-quote (dow (string-to-number (match-string 3))
                             (string-to-number (match-string 1))
                             (string-to-number (match-string 2))))
         ">"))
 nil nil nil nil nil)

(Por supuesto, todos los argumentos nil opcionales pueden omitirse).

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top

web tasarım