Как определить, является ли текущий символ буквой

9

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

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

Обновление К сожалению, мое предположение об эквивалентности класса букв и класса синтаксиса [:alpha:]представляется неверным.

имя
источник

Ответы:

9

Используйте свойства символов Юникода

Это должно определенно работать:

(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заглавными и не спрашивают меня, какие остальные).

Malabarba
источник
Большое спасибо, это решает проблему, ۱۲۳۴۵۶۷۸۹۰но есть некоторые негативы, например, арабский или иврит алеф: א, ا.
Имя
@Name Исправлено. Попробуйте снова.
Малабарба
2
Еще раз спасибо Я проверил это с различными алфавитами, и это работает. Единственное исключение, которое я нашел, - это некоторые азиатские алфавиты, такие как китайский en.wikipedia.org/wiki/Chinese_numerals или японский en.wikipedia.org/wiki/Japanese_numerals . Например считается число 5на японском языке. Ваш код считает это письмо. Может быть, это буква (как в римском номере v). Может быть, кто-то, кто знаком с японским языком, может это проверить.
Имя
1
это как английское слово five, так что это буква. При написании числа 5 вместо слова пять они используют 5точно так же, как английский.
Мьюр
8

РЕДАКТИРОВАТЬ: Этот ответ должен быть полностью действительным в 25,5 (где ошибка была исправлена). Для более старых версий используйте другой вариант .


Это должно сказать вам, если текущий символ является буквой, и должен работать на любом языке.

 (looking-at-p "[[:alpha:]]")
Malabarba
источник
Большое спасибо, мне просто любопытно, какая разница между looking-at-pвашим решением и looking-atдругим ответом.
Имя
1
Эти две функции эквивалентны, за исключением того, что looking-at-pне устанавливает данные о совпадении.
JCH
1
@Name look-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 ...) как буквы.
Имя
Легко исправимо
abo-abo
Большое спасибо еще раз. Еще один ложный положительный результат: он рассматривает ۹(то есть, индийскую цифру 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)))
wvxvw
источник