Cómo determinar si el carácter actual es una letra

9

Cómo puedo determinar si el carácter actual es una letra (un carácter alfabético) (es decir, pertenece a la clase de sintaxis [:alpha:]en las nociones de expresiones regulares). Me gustaría escribir una función simple como la siguiente:

(defun test-letter () (interactive)
(if char-after-is-a-letter
    (message "This is a letter")
    (message "This is not a letter")
    )
)

Actualización Desafortunadamente, mi suposición sobre la equivalencia de la clase de las letras y la clase de sintaxis [:alpha:]parece ser falsa.

Nombre
fuente

Respuestas:

9

Usar propiedades de caracteres Unicode

Esto definitivamente debería funcionar:

(memq (get-char-code-property (char-after) 'general-category)
      '(Ll Lu Lo Lt Lm Mn Mc Me Nl))

Como beneficio adicional, también debería ser más rápido que looking-at.


Emacs almacena todas las propiedades de caracteres especificadas por el estándar Unicode. Son accesibles con get-char-code-property. Específicamente, la general-categorypropiedad especifica qué caracteres son letras ( Llson minúsculas, Lumayúsculas y no me preguntan cuáles son los otros).

Malabarba
fuente
Muchas gracias, esto resuelve el problema ۱۲۳۴۵۶۷۸۹۰pero hay algunos negativos verdaderos, por ejemplo, árabe o hebreo Alef: א, ا.
Nombre
@ Nombre fijo. Vuelve a intentarlo.
Malabarba
2
Gracias de nuevo. Lo revisé con varios alfabetos y funciona. La única excepción que encontré es con un alfabeto asiático como el chino en.wikipedia.org/wiki/Chinese_numerals o japonés en.wikipedia.org/wiki/Japanese_numerals . Por ejemplo, se considera como el número 5en japonés. Su código considera esto una carta. Tal vez es una letra (como en número romano v). Quizás alguien que esté familiarizado con el japonés pueda verificar esto.
Nombre
1
es como la palabra inglesa five, entonces es una letra. Cuando escriben el número 5 en lugar de la palabra cinco, usan 5igual que el inglés.
Muir
8

EDITAR: Esta respuesta debería ser perfectamente válida en 25.5 (donde se había solucionado el error ). Para versiones anteriores, use la otra opción .


Esto debería decirle si el carácter actual es una letra, y debería funcionar en cualquier idioma.

 (looking-at-p "[[:alpha:]]")
Malabarba
fuente
Muchas gracias, solo tengo curiosidad sobre la diferencia entre el looking-at-puso en su solución y looking-atla otra respuesta.
Nombre
1
Las dos funciones son equivalentes, excepto que looking-at-pno establece datos de coincidencia.
jch
1
@Name looking-at-p está más cerca de un predicado puro, porque no establece los datos de coincidencia. Si anteriormente realizó algo como una búsqueda hacia adelante, match-string(y sus muchos hermanos) devolverá el resultado de la búsqueda. Mientras tanto, con la versión no predicada, match-string devolverá el resultado de la coincidencia de mirar.
Malabarba
5

Creo que puedes salirte con la tuya:

(defun test-letter ()
  (interactive)
  (let ((char (char-after)))
    (if (and (eq (char-syntax char) ?w)
             (or (> char ?9)
                 (< char ?1)))
        (message "This is a letter")
      (message "This is not a letter"))))

Actualizar

Esto es menos eficiente, pero más cercano a lo que quieres:

(defun test-letter ()
  (interactive)
  (if (looking-at "[a-z-A-Z]")
      (message "This is a letter")
    (message "This is not a letter")))
abo-abo
fuente
Gracias, un posible problema: esta función considera los dígitos (123 ...) como una letra.
Nombre
Fácilmente reparable.
abo-abo
Muchas gracias de nuevo. Otro falso positivo: Esto considera ۹(es decir, el dígito indio 9) o ٪como una letra.
Nombre
1
Su primera solución estuvo bien con letras griegas (como ζo α), pero la actualización no.
Nombre
Pero combinar ambos es una solución más cercana.
Nombre
2

En caso de que estuviera muy preocupado por los caracteres nacionales y el tratamiento preciso de las clases de caracteres Unicode, la única solución que pude encontrar hasta ahora es la regexbiblioteca Python . Ambos grepy Perl(¡para mi sorpresa!) No hicieron el trabajo correctamente.

Por lo tanto, la expresión regular que está después es la siguiente: \p{L}. Esto se conoce como versión abreviada de la propiedad Unicode, la versión completa es \p{Letter}o incluso p\{General_Category=Letter}. Letteres en sí misma una clase compuesta, pero no entraré en detalles, la mejor referencia que pude encontrar sobre el tema está aquí .

La biblioteca de Python no está integrada en el lenguaje (es una alternativa a la rebiblioteca integrada ). Entonces, necesitaría instalarlo, por ejemplo:

# pip install regex

Entonces, puedes usarlo así:

import regex
>>> regex.match(ur'\p{L}+', u'۱۲۳۴۵۶۷۸۹۰')
>>> regex.match(ur'\p{L}+', u'абвгд')
<regex.Match object; span=(0, 5), match=u'\u0430\u0431\u0432\u0433\u0434'>
>>> regex.match(ur'\p{L}+', u'123')
>>> regex.match(ur'\p{L}+', u'abcd')
<regex.Match object; span=(0, 4), match=u'abcd'>
>>> 

También podría colocar este script en algún lugar donde pueda acceder a él:

#!/usr/bin/env python
import regex
import sys

if __name__ == "__main__":
    for match in regex.finditer(ur'\p{L}+', sys.argv[1].decode('utf-8')):
        print match.string

Y llámelo desde Emacs así (supongamos que guardó este script en ~/bin):

(defun unicode-character-p ()
  (interactive)
  (let* ((current (char-after (point)))
         (result (shell-command-to-string
                  (format "~/bin/is-character.py '%c'" current))))
    (message
     (if (string= result "") "Character %c isn't a letter"
        "Character %c is a letter")
     current)))
wvxvw
fuente