Come determinare se il personaggio attuale è una lettera


9

Come posso determinare se il carattere corrente è una lettera (un carattere alfabetico) (cioè appartiene alla classe di sintassi [:alpha:]nelle nozioni regexp). Vorrei scrivere una semplice funzione come di seguito:

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

Aggiornamento Purtroppo la mia ipotesi sull'equivalenza della classe delle lettere e della classe di sintassi [:alpha:]sembra essere falsa.

Risposte:


9

Usa proprietà char Unicode

Questo dovrebbe sicuramente funzionare:

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

Come bonus dovrebbe anche essere più veloce di looking-at.


Emacs memorizza tutte le proprietà dei caratteri specificate dallo standard Unicode. Sono accessibili con get-char-code-property. Nello specifico, la general-categoryproprietà specifica quali caratteri sono lettere ( Llsono minuscole, Lumaiuscole e non chiedermi quali sono gli altri).


Mille grazie, questo risolve il problema ۱۲۳۴۵۶۷۸۹۰ma ci sono alcuni aspetti negativi, ad esempio l'arabo o l'ebraico Alef: א, ا.
Nome

@Name Risolto. Ritenta.
Malabarba,

2
Grazie ancora. L'ho controllato con vari alfabeti e funziona. L'unica eccezione che ho trovato è con qualche alfabeto asiatico come il cinese en.wikipedia.org/wiki/Chinese_numerals o il giapponese en.wikipedia.org/wiki/Japanese_numerals . Ad esempio, è considerato il numero 5in giapponese. Il tuo codice considera questa una lettera. Forse è una lettera (come nel numero romano v). Forse qualcuno che ha familiarità con il giapponese può verificarlo.
Nome

1
è come la parola inglese five, quindi è una lettera. Quando scrivono il numero 5 anziché la parola cinque, usano 5proprio come l'inglese.
Muir,

8

EDIT: questa risposta dovrebbe essere perfettamente valida in 25.5 (dove il bug era stato corretto). Per le versioni precedenti, utilizzare l' altra opzione .


Questo dovrebbe dirti se il carattere corrente è una lettera e dovrebbe funzionare in qualsiasi lingua.

 (looking-at-p "[[:alpha:]]")

Molte grazie, sono solo curioso della differenza tra looking-at-pusato nella tua soluzione e looking-atnell'altra risposta.
Nome

1
Le due funzioni sono equivalenti, tranne per il fatto che looking-at-pnon imposta i dati di corrispondenza.
dal

1
@Name looking-at-p è più vicino a un predicato puro, perché non imposta i dati di corrispondenza. Se in precedenza hai eseguito qualcosa di simile a una ricerca in avanti, match-string(e i suoi numerosi fratelli) restituirà il risultato della ricerca. Nel frattempo, con la versione non predicata, match-string restituirà il risultato della corrispondenza di ricerca.
Malabarba,

5

Penso che tu possa cavartela con questo:

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

Aggiornare

Questo è meno efficiente, ma più vicino a quello che vuoi:

(defun test-letter ()
  (interactive)
  (if (looking-at "[a-z-A-Z]")
      (message "This is a letter")
    (message "This is not a letter")))

Grazie, un possibile problema: questa funzione considera le cifre (123 ...) come una lettera.
Nome

Facilmente risolvibile
abo-ABO

Mille grazie ancora. Un altro falso positivo: questo considera ۹(cioè la cifra indiana 9) o ٪come una lettera.
Nome

1
La tua prima soluzione andava bene con lettere greche (come ζo α), ma l'aggiornamento non lo è.
Nome

Ma combinare entrambi è una soluzione più vicina.
Nome

2

Nel caso in cui tu fossi molto preoccupato per i personaggi nazionali e il trattamento preciso delle classi di caratteri Unicode, l'unica soluzione che sono riuscito a trovare finora è la regexlibreria Python . Entrambi grepe Perl(con mia grande sorpresa!) Non hanno fatto bene il lavoro.

Così, l'espressione regolare si sono dopo è questo: \p{L}. Questa è nota come versione abbreviata della proprietà Unicode, la versione completa è \p{Letter}o anche p\{General_Category=Letter}. Letterè di per sé una classe composita, ma non entrerò nei dettagli, il miglior riferimento che ho potuto trovare sull'argomento è qui .

La libreria Python non è integrata nel linguaggio (è un'alternativa alla relibreria integrata ). Quindi, dovresti installarlo, ad esempio:

# pip install regex

Quindi, potresti usarlo in questo modo:

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

Puoi anche mettere questo script da qualche parte dove puoi accedervi:

#!/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 chiamalo da Emacs in questo modo (supponi di aver salvato questo script in ~/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)))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.