¿Cómo buscar una palabra árabe en texto sin sus signos diacríticos / acentos?

11

En árabe, como en algunos otros idiomas, existe lo que se llama diacríticos para mejorar la pronunciación. No existe una convención sobre cuántos signos diacríticos se deben escribir para una sola palabra. Algunos usan el mínimo (que prefiero) lo suficiente para desambiguar la pronunciación, mientras que otros los usan de manera superflua o solo con fines caligráficos estéticos. Por lo tanto, hay una amplia variación sobre qué y cuántos diacríticos están asociados con una palabra. Cuando lo hago isearch-forward/backwardpresionando C-s/r, surge un problema cuando lo escribo en el minibúfer de búsqueda sin signos diacríticos, no coincidirá con la misma palabra en el texto si tuviera signos diacríticos, lo que hace que la tarea de buscar esta palabra con sus signos diacríticos potenciales sea insatisfactoria.

¿Hay alguna manera de hacer que la búsqueda / búsqueda regular no sea consciente de los signos diacríticos? Espero que haya una respuesta que pueda extenderse para incluir regexp C-M-s/ry grepbuscar que uso con bastante frecuencia en helm-projectile para buscar una palabra en proyectos de látex de varios archivos.

Actualización
Sería bueno ver que Emacs en todas sus funciones de búsqueda realiza el paso de eliminación del texto (de acentos / signos diacríticos / lo que sea) antes de que coincida con el paso como un comportamiento predeterminado que puede ser desactivado por un prefijo a pedido no importa qué idioma tengamos a mano. Por lo general, cuando busco algo que no espero que el mejor editor (Emacs) falle en este recado solo por algunos signos diacríticos o acentos que rara vez se necesitan para realizar tareas de texto mundanas.

doctorado
fuente
1
Mira las ucs-normalize-*funciones en lisp/international/ucs-normalize.el. No existe un plegado de búsqueda predefinido para esos, como ocurre con el plegado de mayúsculas y minúsculas, pero al menos puede normalizar una región antes de buscarla. Una buena implementación es probablemente una tarea bastante compleja.
Ted Zlatanov
¿Puede ayudar superuser.com/a/675172/233868 ?
Nombre
@Nombre, el árabe tiene muchas más posibilidades de combinaciones de letras (26) con acentos / signos diacríticos, por lo que no es para el árabe. Parece que no hay sustituto para las bibliotecas específicas del idioma. No puedo creer que esto ya se haya implementado en Microsoft Word y no en Emacs todos esos años atrás.
doctorado
1
El árabe tiene alrededor de 80 signos diacríticos y 26 letras, por lo que hacer todas las combinaciones es una tarea desalentadora. Debe haber alguna forma de quitar el texto de sus signos diacríticos, como lo que se phpimplementó en : stackoverflow.com/a/25563250/1288722 - también implementado en Javascript: stackoverflow.com/a/7193622/1288722
doctorado
Pensamiento: ¿no es posible ejecutar la cadena a través de esa función de limpieza de php y luego pasar el resultado a algo similar a helm-swoop?
Sean Allred

Respuestas:

5

Aquí hay un comienzo difícil, basado en la lista de caracteres combinados en esta respuesta (y luego extendida). (Marcar esto como wiki de la comunidad - ¡edite y mejore esto!)

(defconst arabic-diacritics '(#x064b #x064c #x064d #x064e #x064f #x0650 #x0651 #x0652 #x0653 #x0654 #x0655 #x0670)
  "Unicode codepoints for Arabic combining characters.")
(defconst arabic-diacritics-regexp (regexp-opt (mapcar #'string arabic-diacritics)))

(defconst arabic-equivalents
  '(
    ;; "alef" is equivalent to "alef with hamza above" etc
    (#x0627 #x0623 #x0625 #x0622)))

;; (require 'cl-lib)    
;; (defun arabic-strip-diacritics (string)
;;   (cl-reduce (lambda (s c) (remove c s)) arabic-diacritics :initial-value string))

(defun arabic-search-without-diacritics (string)
  (interactive (list (read-string "Search for: " nil nil nil t)))
  (let ((regexp
         (apply #'concat
                (mapcar (lambda (c)
                          (let ((equivalents (assq c arabic-equivalents)))
                            (concat
                             (if equivalents
                                 (regexp-opt (mapcar #'string equivalents))
                               (regexp-quote (string c)))
                             arabic-diacritics-regexp "*")))
                        string))))
    (search-forward-regexp regexp)))

Entonces, si un búfer contiene "الْحَمْدُ لِلَّهِ رَبِّ الْعَالَمِينَ", y lo evalúo (arabic-search-without-diacritics "الحمد لله رب العالمين"), encuentra el texto. También funciona de forma interactiva, como M-x arabic-search-without-diacritics.

Enfoque alternativo:

Aquí hay un ejemplo de código completo que demuestra cómo Mnse pueden eliminar las marcas diacríticas y otras marcas ( propiedad) no espaciadoras de las cadenas normalizadas en las coincidencias de expresiones regulares . Funciona con los ejemplos dados y la OMI es el enfoque correcto.

(defun kill-marks (string)
  (concat (loop for c across string
                when (not (eq 'Mn (get-char-code-property c 'general-category)))
                collect c)))

(let* ((original1 "your Arabic string here")
      (normalized1 (ucs-normalize-NFKD-string original1))
      (original2 "your other Arabic string here")
      (normalized2 (ucs-normalize-NFKD-string original2)))
  (equal
   (replace-regexp-in-string "." 'kill-marks normalized1)
   (replace-regexp-in-string "." 'kill-marks normalized2)))
legoscia
fuente
Agregué dos diacríticos más comúnmente usados ​​en árabe a su buena lista. Esta es la lista ordenada completa 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1648: tarifa gratuita para actualizar.
Doctorado
La primera función arabic-search-without-diacriticsfunciona bien pero se rompe con algunas palabras, no sé por qué como esta الأَ. Otra advertencia, siempre tengo que establecer el método de entrada en árabe cuando ingreso mi cadena en el mini buffer, mientras que en la isearch-forward/backwardfunción permanece allí.
Doctorado
kill-markses el mejor enfoque para proporcionar texto sin complicaciones listo para todo tipo de búsqueda. Lo que no está claro para mí es cómo implementar eso en un búfer completo y luego en múltiples archivos.
doctorado
1
¡Gracias! ¿Es posible hacer que isearch-forward/backwardresalte todos los sucesos y el actual de manera diferente y al invocar savanzará y rretrocederá?
doctorado
2
Discusión sobre emacs-devel: thread.gmane.org/gmane.emacs.devel/182483
Ted Zlatanov