Como determinar se o caractere atual é uma letra

9

Como posso determinar se o caractere atual é uma letra (um caractere alfabético) (isto é, pertence à classe de sintaxe [:alpha:]nas noções de expressão regular). Gostaria de escrever uma função simples como abaixo:

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

Atualização Infelizmente, minha suposição sobre a equivalência da classe das letras e da classe da sintaxe [:alpha:]parece ser falsa.

Nome
fonte

Respostas:

9

Usar propriedades de caracteres Unicode

Definitivamente, isso deve funcionar:

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

Como bônus, também deve ser mais rápido que looking-at.


O Emacs armazena todas as propriedades de caracteres especificadas pelo padrão Unicode. Eles são acessíveis com get-char-code-property. Especificamente, a general-categorypropriedade especifica quais caracteres são letras ( Llsão minúsculas, Lumaiúsculas e não me perguntam o que os outros são).

Malabarba
fonte
Muito obrigado, isso resolve o problema, ۱۲۳۴۵۶۷۸۹۰mas existem alguns negativos verdadeiros, por exemplo, árabe ou hebraico Alef: א, ا.
Name
@Name Fixed. Tente de novo.
Malabarba
2
Mais uma vez obrigado. Eu verifiquei com vários alfabetos e funciona. A única exceção que encontrei foi em alguns alfabetos asiáticos, como chinês en.wikipedia.org/wiki/Chinese_numerals ou japonês en.wikipedia.org/wiki/Japanese_numerals . Por exemplo, é considerado como o número 5em japonês. Seu código considera isso uma carta. Talvez seja uma letra (como em número romano v). Talvez alguém familiarizado com o japonês possa verificar isso.
Nome
11
é como a palavra em inglês five, por isso é uma letra. Ao escrever o número 5, em vez da palavra cinco, eles usam 5exatamente como o inglês.
Muir
8

EDIT: Esta resposta deve ser perfeitamente válida em 25.5 (onde o bug foi corrigido). Para versões mais antigas, use a outra opção .


Isso deve indicar se o caractere atual é uma letra e deve funcionar em qualquer idioma.

 (looking-at-p "[[:alpha:]]")
Malabarba
fonte
Muito obrigado, estou curioso sobre a diferença entre looking-at-pusado na sua solução e looking-atna outra resposta.
Nome
11
As duas funções são equivalentes, exceto que looking-at-pnão define dados de correspondência.
jch 15/02
11
O @Name olhando para p está mais próximo de um predicado puro, porque não define os dados da correspondência. Se você já realizou algo como uma busca avançada match-string(e seus muitos irmãos) retornará o resultado da pesquisa. Enquanto isso, com a versão não predicada, a sequência de caracteres retornará o resultado da correspondência visual.
Malabarba
5

Eu acho que você pode se safar com isso:

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

Atualizar

Isso é menos eficiente, mas mais próximo do que você deseja:

(defun test-letter ()
  (interactive)
  (if (looking-at "[a-z-A-Z]")
      (message "This is a letter")
    (message "This is not a letter")))
abo-abo
fonte
Obrigado, um possível problema: Esta função considera os dígitos (123 ...) como uma letra.
Nome
Facilmente corrigível.
abo-abo
Muito obrigado novamente. Outro falso positivo: considera ۹(ou seja, o dígito indiano 9) ou ٪como uma letra.
Nome
11
Sua primeira solução foi boa com letras gregas (como ζou α), mas a atualização não é.
Nome
Mas combinar as duas é uma solução mais próxima.
Nome
2

Caso você estivesse muito preocupado com os caracteres nacionais e com o tratamento preciso das classes de caracteres Unicode, a única solução que encontrei até agora é a regexbiblioteca Python . Ambos grepe Perl(para minha total surpresa!) Não fizeram o trabalho corretamente.

Assim, a expressão regular que você está depois é este: \p{L}. Isso é conhecido como versão abreviada da propriedade Unicode, a versão completa é \p{Letter}ou mesmo p\{General_Category=Letter}. Letteré uma classe composta, mas não vou entrar em detalhes, a melhor referência que pude encontrar sobre o assunto está aqui .

A biblioteca Python não está embutida na linguagem (é uma alternativa à rebiblioteca embutida ). Então, você precisaria instalá-lo, por exemplo:

# pip install regex

Então, você pode usá-lo da seguinte maneira:

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

Você também pode colocar esse script em algum lugar onde você pode acessá-lo:

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

E chame-o do Emacs assim (suponha que você tenha salvo esse 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
fonte