So stellen Sie fest, ob das aktuelle Zeichen ein Buchstabe ist

9

Wie ich feststellen kann, ob das aktuelle Zeichen ein Buchstabe (ein alphabetisches Zeichen) ist (dh zur [:alpha:]Syntaxklasse in regulären Ausdrücken gehört). Ich möchte eine einfache Funktion wie folgt schreiben:

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

Update Leider [:alpha:]scheint meine Annahme über die Äquivalenz der Buchstabenklasse und der Syntaxklasse falsch zu sein.

Name
quelle

Antworten:

9

Verwenden Sie Unicode-Char-Eigenschaften

Das sollte auf jeden Fall funktionieren:

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

Als Bonus sollte es auch schneller sein als looking-at.


Emacs speichert alle im Unicode-Standard angegebenen Zeicheneigenschaften. Sie sind zugänglich mit get-char-code-property. Insbesondere gibt die general-categoryEigenschaft an, welche Zeichen Buchstaben sind ( LlKleinbuchstaben, LuGroßbuchstaben und fragen Sie mich nicht, was die anderen sind).

Malabarba
quelle
Vielen Dank, dies löst das Problem mit, ۱۲۳۴۵۶۷۸۹۰aber es gibt einige echte Negative, z. B. Arabisch oder Hebräisch Alef: א, ا.
Name
@ Name behoben. Versuchen Sie es erneut.
Malabarba
2
Danke nochmal. Ich habe es mit verschiedenen Alphabeten überprüft und es funktioniert. Die einzige Ausnahme, die ich gefunden habe, ist bei einigen asiatischen Alphabeten wie Chinesisch en.wikipedia.org/wiki/Chinese_numerals oder Japanisch en.wikipedia.org/wiki/Japanese_numerals . Zum Beispiel wird als die Nummer 5in Japanisch betrachtet. Ihr Code betrachtet dies als einen Brief. Vielleicht ist es ein Buchstabe (wie in römischer Zahl v). Vielleicht kann jemand, der mit Japanisch vertraut ist, dies überprüfen.
Name
1
ist wie das englische Wort five, also ist es ein Buchstabe. Wenn sie die Nummer 5 anstelle des Wortes fünf schreiben, verwenden sie 5genau wie Englisch.
Muir
8

BEARBEITEN: Diese Antwort sollte in 25.5 (wo der Fehler behoben wurde) vollkommen gültig sein . Verwenden Sie für ältere Versionen die andere Option .


Dies sollte Ihnen sagen, ob das aktuelle Zeichen ein Buchstabe ist und in jeder Sprache funktionieren sollte.

 (looking-at-p "[[:alpha:]]")
Malabarba
quelle
Vielen Dank, ich bin nur neugierig auf den Unterschied zwischen der looking-at-pVerwendung in Ihrer Lösung und looking-atder anderen Antwort.
Name
1
Die beiden Funktionen sind äquivalent, außer dass looking-at-pkeine Übereinstimmungsdaten festgelegt werden.
jch
1
@Name Looking-at-P kommt einem reinen Prädikat näher, da die Übereinstimmungsdaten nicht festgelegt werden. Wenn Sie zuvor so etwas wie eine Vorwärtssuche durchgeführt haben match-string(und seine vielen Geschwister), wird das Ergebnis der Suche zurückgegeben. In der Nicht-Prädikat-Version gibt die Übereinstimmungszeichenfolge das Ergebnis der betrachteten Übereinstimmung zurück.
Malabarba
5

Ich denke, Sie können damit durchkommen:

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

Aktualisieren

Dies ist weniger effizient, aber näher an dem, was Sie wollen:

(defun test-letter ()
  (interactive)
  (if (looking-at "[a-z-A-Z]")
      (message "This is a letter")
    (message "This is not a letter")))
abo-abo
quelle
Danke, ein mögliches Problem: Diese Funktion betrachtet die Ziffern (123 ...) als Buchstaben.
Name
Leicht zu reparieren.
abo-abo
Vielen Dank nochmal. Ein weiteres falsches Positiv: Dies gilt ۹(dh die indische Ziffer 9) oder ٪als Buchstabe.
Name
1
Ihre erste Lösung war gut mit griechischen Buchstaben (wie ζoder α), aber das Update ist nicht.
Name
Beides zu kombinieren ist jedoch eine engere Lösung.
Name
2

Falls Sie sehr besorgt über nationale Zeichen und die genaue Behandlung von Unicode-Zeichenklassen waren, ist die einzige Lösung, die ich bisher finden konnte, die Python- regexBibliothek . Beide grepund Perl(zu meiner großen Überraschung!) Haben den Job nicht richtig gemacht.

Der reguläre Ausdruck, nach dem Sie suchen, lautet also : \p{L}. Dies ist als Unicode-Eigenschafts-Kurzversion bekannt, die Vollversion ist \p{Letter}oder sogar p\{General_Category=Letter}. Letterist selbst eine zusammengesetzte Klasse, aber ich werde nicht auf Details eingehen. Die beste Referenz, die ich zu diesem Thema finden konnte, ist hier .

Die Python-Bibliothek ist nicht in die Sprache integriert (eine Alternative zur integrierten reBibliothek). Sie müssten es also installieren, zum Beispiel:

# pip install regex

Dann könnten Sie es so verwenden:

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

Sie können dieses Skript auch an einer Stelle ablegen, an der Sie darauf zugreifen können:

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

Und nennen Sie es von Emacs so (nehmen Sie an, Sie haben dieses Skript in gespeichert ~/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
quelle