Comment déterminer si le caractère actuel est une lettre

9

Comment puis-je déterminer si le caractère actuel est une lettre (un caractère alphabétique) (c'est-à-dire appartient à la classe de syntaxe [:alpha:]dans les notions d'expression régulière). Je voudrais écrire une fonction simple comme ci-dessous:

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

Mise à jour Malheureusement, mon hypothèse sur l'équivalence de la classe des lettres et de la classe de syntaxe [:alpha:]semble fausse.

Nom
la source

Réponses:

9

Utiliser les propriétés de caractère Unicode

Cela devrait certainement fonctionner:

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

En prime, il devrait également être plus rapide que looking-at.


Emacs stocke toutes les propriétés de caractères spécifiées par la norme Unicode. Ils sont accessibles avec get-char-code-property. Plus précisément, la general-categorypropriété spécifie quels caractères sont des lettres ( Llsont en minuscules, en Lumajuscules et ne me demandez pas quels sont les autres).

Malabarba
la source
Merci beaucoup, cela résout le problème ۱۲۳۴۵۶۷۸۹۰mais il y a quelques vrais négatifs, par exemple l'arabe ou l'hébreu Alef: א, ا.
Nom
@Name Fixed. Essaye encore.
Malabarba
2
Merci encore. Je l'ai vérifié avec différents alphabets et cela fonctionne. La seule exception que j'ai trouvée concerne certains alphabets asiatiques tels que le chinois en.wikipedia.org/wiki/Chinese_numerals ou le japonais en.wikipedia.org/wiki/Japanese_numerals . Par exemple, est considéré comme le nombre 5en japonais. Votre code considère cela comme une lettre. C'est peut-être une lettre (comme en chiffre romain v). Peut-être que quelqu'un qui connaît le japonais peut le vérifier.
Nom
1
est comme le mot anglais five, donc c'est une lettre. Lors de l'écriture du chiffre 5 au lieu du mot cinq, ils utilisent 5exactement comme l'anglais.
Muir
8

EDIT: Cette réponse devrait être parfaitement valide en 25.5 (où le bug avait été corrigé). Pour les versions plus anciennes, utilisez l' autre option .


Cela devrait vous dire si le caractère actuel est une lettre et devrait fonctionner dans n'importe quelle langue.

 (looking-at-p "[[:alpha:]]")
Malabarba
la source
Merci beaucoup, je suis simplement curieux de savoir la différence entre looking-at-putilisé dans votre solution et looking-atdans l'autre réponse.
Nom du
1
Les deux fonctions sont équivalentes, sauf que looking-at-pcela ne définit pas les données de correspondance.
jch
1
@Name looking-at-p est plus proche d'un pur prédicat, car il ne définit pas les données de correspondance. Si vous avez déjà effectué quelque chose comme une recherche en avant, match-string(et ses nombreux frères et sœurs) renverra le résultat de la recherche. Pendant ce temps, avec la version non prédicat, match-string retournera le résultat de la correspondance en cours.
Malabarba
5

Je pense que vous pouvez vous en sortir:

(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"))))

Mise à jour

C'est moins efficace, mais plus proche de ce que vous voulez:

(defun test-letter ()
  (interactive)
  (if (looking-at "[a-z-A-Z]")
      (message "This is a letter")
    (message "This is not a letter")))
abo-abo
la source
Merci, un problème possible: Cette fonction considère les chiffres (123 ...) comme une lettre.
Nom du
Facilement réparable.
abo-abo
Merci encore. Autre faux positif: cela considère ۹(c'est-à-dire le chiffre indien 9) ou ٪comme une lettre.
Nom du
1
Votre première solution était bien avec les lettres grecques (comme ζou α), mais la mise à jour ne l'est pas.
Nom du
Mais combiner les deux est une solution plus étroite.
Nom du
2

Au cas où vous seriez très préoccupé par les caractères nationaux et le traitement précis des classes de caractères Unicode, alors la seule solution que j'ai pu trouver jusqu'à présent est la regexbibliothèque Python . Les deux grepet Perl(à ma grande surprise!) N'ont pas fait le travail correctement.

Ainsi, l'expression régulière que vous êtes est après celui - ci: \p{L}. Ceci est connu comme la version abrégée de la propriété Unicode, la version complète est \p{Letter}ou même p\{General_Category=Letter}. Letterest en soi une classe composite, mais je n'entrerai pas dans les détails, la meilleure référence que j'ai pu trouver sur le sujet est ici .

La bibliothèque Python n'est pas intégrée au langage (c'est une alternative à la rebibliothèque intégrée). Vous devez donc l'installer, par exemple:

# pip install regex

Ensuite, vous pouvez l'utiliser comme ceci:

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'>
>>> 

Vous pouvez également placer ce script quelque part où vous pouvez y accéder:

#!/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

Et appelez-le depuis Emacs comme ceci (supposons que vous ayez enregistré ce script ~/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
la source