Як визначити, чи є поточний символ буквою


9

Як я можу визначити, чи поточний символ є буквою (алфавітним символом) (тобто належить до класу синтаксису [:alpha:]в поняттях regexp). Я хотів би написати просту функцію, як показано нижче:

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

Оновлення На жаль, моє припущення про еквівалентність класу букв та класу синтаксису [:alpha:]здається помилковим.

Відповіді:


9

Використовуйте властивості знаків Unicode

Це обов'язково має працювати:

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

Як бонус він також повинен бути швидшим, ніж looking-at.


Emacs зберігає всі властивості символів, визначені стандартом Unicode. Вони доступні за допомогою get-char-code-property. Зокрема, general-categoryвластивість визначає, якими символами є літери ( Llмалими літерами, Luвеликими літерами, і не запитувати мене, що таке інші).


Велике спасибі, це вирішує проблему, ۱۲۳۴۵۶۷۸۹۰але є деякі правдиві негативи, наприклад, арабська або іврит Алеф: א, ا.
Ім'я

@ Ім'я виправлено. Спробуйте ще раз.
Малабарба

2
Ще раз дякую вам. Я перевірив це за допомогою різних алфавітів, і він працює. Єдине виключення, яке я знайшов, - це азіатський алфавіт, наприклад китайський en.wikipedia.org/wiki/Chinese_numerals або японський en.wikipedia.org/wiki/Japans_numerals . Наприклад , вважається число 5японською мовою. Ваш код вважає це листом. Можливо, це лист (як у римському номері v). Можливо, хтось, хто знайомий з японською мовою, може це перевірити.
Ім'я

1
- це як англійське слово five, значить, це літера. При написанні цифри 5 замість слова п’ять вони використовують так 5само, як англійська.
Муїр

8

EDIT: Ця відповідь має бути абсолютно достовірною в 25.5 (там, де виправлено помилку ). Для старих версій використовуйте інший варіант .


Це повинно вам сказати, чи є поточна знакова літера і чи має працювати будь-якою мовою.

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

Велике спасибі, мені просто цікаво про різницю між looking-at-pвикористаними у вашому рішенні та looking-atіншими відповідями.
Ім'я

1
Дві функції еквівалентні, за винятком тих, що looking-at-pне встановлюють дані відповідності.
jch

1
@Name looking-at-p ближче до чистого предиката, оскільки він не встановлює дані відповідності. Якщо ви раніше виконували щось на кшталт пошуку вперед, match-string(і його багато братів і сестер) повернуть результат пошуку. Тим часом, з не-предикатною версією, match-string поверне результат перегляду матчу.
Малабарба

5

Я думаю, що ти можеш уникнути цього:

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

Оновлення

Це менш ефективно, але ближче до того, що ви хочете:

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

Дякую, можлива проблема: Ця функція розглядає цифри (123 ...) як букву.
Ім'я

Легко фіксується.
або-або

Ще раз дякую. Ще один хибний позитив: це розглядає ۹(тобто індійську цифру 9) або ٪як букву.
Ім'я

1
Ваше перше рішення було чудово з грецькими літерами (наприклад, ζабо α), але оновлення - ні.
Ім'я

Але поєднання обох - це більш тісне рішення.
Ім'я

2

Якщо ви були дуже стурбовані національними символами та точним поводженням з класами символів Unicode, єдине рішення, яке мені вдалося знайти поки що, - це regexбібліотека Python . І ті, grepі Perl(на моє повне здивування!) Не виконали цю роботу належним чином.

Таким чином, регулярний вираз ви після це одна: \p{L}. Це відоме як скорочена версія властивості Unicode, повна версія є \p{Letter}або навіть p\{General_Category=Letter}. Letterсам по собі складений клас, але я не буду вникати в деталі, найкраща посилання, яку я міг би знайти в цьому питанні, тут .

Бібліотека Python не вбудована в мову (це альтернатива вбудованій reбібліотеці). Отже, вам потрібно буде встановити його, наприклад:

# pip install regex

Потім ви можете використовувати його так:

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

Ви також можете помістити цей скрипт де-небудь, де ви можете отримати до нього доступ:

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

І називайте його від Emacs так (припустимо, ви зберегли цей скрипт у ~/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)))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.