Jak ustalić, czy bieżącym znakiem jest litera


9

Jak mogę ustalić, czy bieżącym znakiem jest litera (znak alfabetyczny) (tzn. Należy do klasy składni [:alpha:]w wyrażeniach regularnych). Chciałbym napisać prostą funkcję jak poniżej:

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

Aktualizacja Niestety moje założenie dotyczące równoważności klasy liter i klasy składni [:alpha:]wydaje się fałszywe.

Odpowiedzi:


9

Użyj właściwości znaków Unicode

To zdecydowanie powinno działać:

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

Jako bonus powinien być również szybszy niż looking-at.


Emacs przechowuje wszystkie właściwości znaków określone przez standard Unicode. Są dostępne za pomocą get-char-code-property. W szczególności general-categorywłaściwość określa, które znaki są literami ( Llmałymi, Luwielkimi i nie pytaj mnie, jakie są inne).


Wielkie dzięki, to rozwiązuje problem, ۱۲۳۴۵۶۷۸۹۰ale istnieją pewne prawdziwe negatywy, np. Arabski lub hebrajski Alef: א, ا.
— Imię

@Name Naprawiono. Spróbuj ponownie.
— Malabarba

2
Jeszcze raz dziękuję. Sprawdziłem to z różnymi alfabetami i działa. Jedyny wyjątek, jaki znalazłem, dotyczy niektórych alfabetów azjatyckich, takich jak chiński en.wikipedia.org/wiki/Chinese_numerals lub japoński en.wikipedia.org/wiki/Japanese_numerals . Na przykład 五jest uważany za liczbę 5w języku japońskim. Twój kod uważa to za list. Może to jest litera (jak cyfra rzymska v). Może ktoś, kto zna japoński, może to zweryfikować.
— Imię

1
五jest jak angielskie słowo five, więc jest literą. Pisząc cyfrę 5 zamiast słowa pięć, używają 5tak jak angielski.
— Muir

8

EDYCJA: Ta odpowiedź powinna być całkowicie poprawna w 25.5 (tam, gdzie błąd został naprawiony). W przypadku starszych wersji użyj innej opcji .


To powinno ci powiedzieć, czy obecny znak jest literą i powinien działać w dowolnym języku.

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

Bardzo dziękuję, jestem ciekawy różnicy między looking-at-pzastosowanym w twoim rozwiązaniu a looking-atdrugą odpowiedzią.
— Imię i nazwisko

1
Dwie funkcje są równoważne, z wyjątkiem tego, że looking-at-pnie ustawiają danych dopasowania.
— jch

1
@Name looking-at-p jest bliżej czystego predykatu, ponieważ nie ustawia danych dopasowania. Jeśli wcześniej wykonałeś coś w rodzaju wyszukiwania do przodu, match-string(i jego wiele rodzeństwa) zwróci wynik wyszukiwania. Tymczasem w przypadku wersji niep predykatowej łańcuch dopasowania zwróci wynik szukanego dopasowania.
— Malabarba

5

Myślę, że możesz uciec od tego:

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

Aktualizacja

Jest to mniej wydajne, ale bliższe temu, czego chcesz:

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

Dzięki, możliwy problem: Ta funkcja traktuje cyfry (123 ...) jako literę.
— Imię i nazwisko

Łatwo naprawić.
— abo-abo

Jeszcze raz wielkie dzięki. Kolejny fałszywy wynik pozytywny: uznaje to ۹(tj. Cyfrę indyjską 9) lub ٪za literę.
— Imię i nazwisko

1
Twoje pierwsze rozwiązanie było w porządku z greckimi literami (takimi jak ζlub α), ale aktualizacja nie jest.
— Imię i nazwisko

Ale połączenie obu jest bliższym rozwiązaniem.
— Imię i nazwisko

2

Jeśli bardzo martwiłeś się znakami narodowymi i precyzyjnym traktowaniem klas znaków Unicode, to jedynym rozwiązaniem, jakie udało mi się do tej pory znaleźć, jest regexbiblioteka Python . Zarówno grepi Perl(ku mojemu zdziwieniu!) Nie wykonali poprawnie tej pracy.

Tak więc wyrażenie regularne jesteś po to jest jeden: \p{L}. Jest to znane jako wersja skrócona właściwości Unicode, pełna wersja jest \p{Letter}lub nawet p\{General_Category=Letter}. Lettersam w sobie jest klasą złożoną, ale nie będę wchodził w szczegóły, najlepsze referencje, jakie mogłem znaleźć na ten temat, są tutaj .

Biblioteka języka Python nie jest wbudowana w język (jest alternatywą dla rebiblioteki wbudowanej ). Więc musisz go zainstalować, na przykład:

# pip install regex

Następnie możesz użyć go w następujący sposób:

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

Możesz także umieścić ten skrypt gdzieś, gdzie możesz uzyskać do niego dostęp:

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

I tak to nazwij Emacsem (załóżmy, że zapisałeś ten skrypt ~/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)))
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.