Cara menentukan apakah karakter saat ini adalah huruf

9

Bagaimana saya dapat menentukan apakah karakter saat ini adalah huruf (karakter alfabet) (yaitu, milik kelas sintaks [:alpha:]dalam pengertian regexp). Saya ingin menulis fungsi sederhana seperti di bawah ini:

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

Pembaruan Sayangnya, asumsi saya tentang kesetaraan kelas huruf dan kelas sintaksisnya [:alpha:]keliru.

Nama
sumber

Jawaban:

9

Gunakan properti char Unicode

Ini pasti bekerja:

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

Sebagai bonus juga harus lebih cepat daripada looking-at.


Emacs menyimpan semua properti karakter yang ditentukan oleh standar Unicode. Mereka dapat diakses dengan get-char-code-property. Secara khusus, general-categoryproperti menentukan karakter mana yang huruf ( Llhuruf kecil, Luhuruf besar, dan jangan tanya saya apa yang lain).

Malabarba
sumber
Terima kasih banyak, ini menyelesaikan masalah dengan ۱۲۳۴۵۶۷۸۹۰tetapi ada beberapa yang benar-negatif, misalnya Arab atau Ibrani Alef: א, ا.
Nama
@Nama Diperbaiki. Coba lagi.
Malabarba
2
Terima kasih lagi. Saya memeriksanya dengan berbagai Abjad dan berfungsi. Satu-satunya pengecualian yang saya temukan adalah dengan beberapa alfabet Asia seperti Cina en.wikipedia.org/wiki/Chinese_numerals atau Jepang en.wikipedia.org/wiki/Japanese_numerals . Misalnya dianggap sebagai angka 5dalam bahasa Jepang. Kode Anda menganggap ini surat. Mungkin itu surat (seperti dalam nomor romawi v). Mungkin seseorang yang terbiasa dengan bahasa Jepang dapat memverifikasi ini.
Nama
1
seperti kata bahasa Inggris five, jadi itu adalah huruf. Saat menulis angka 5 dan bukan kata lima, mereka menggunakan 5seperti bahasa Inggris.
Muir
8

EDIT: Jawaban ini harus benar-benar valid dalam 25.5 (di mana bug telah diperbaiki). Untuk versi yang lebih lama, gunakan opsi lain .


Ini akan memberi tahu Anda jika karakter saat ini adalah surat, dan harus berfungsi dalam bahasa apa pun.

 (looking-at-p "[[:alpha:]]")
Malabarba
sumber
Terima kasih banyak, saya hanya ingin tahu tentang perbedaan antara yang looking-at-pdigunakan dalam solusi Anda dan looking-atjawaban yang lain.
Nama
1
Kedua fungsi tersebut setara, kecuali yang looking-at-ptidak mengatur data kecocokan.
jch
1
@Name looking-at-p lebih dekat dengan predikat murni, karena tidak mengatur data kecocokan. Jika sebelumnya Anda melakukan sesuatu seperti pencarian-maju, match-string(dan banyak saudara kandungnya) akan mengembalikan hasil pencarian. Sementara itu, dengan versi non-predikat, match-string akan mengembalikan hasil pertandingan yang terlihat.
Malabarba
5

Saya pikir Anda bisa lolos dengan ini:

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

Memperbarui

Ini kurang efisien, tetapi lebih dekat dengan yang Anda inginkan:

(defun test-letter ()
  (interactive)
  (if (looking-at "[a-z-A-Z]")
      (message "This is a letter")
    (message "This is not a letter")))
abo-abo
sumber
Terima kasih, masalah yang mungkin terjadi: Fungsi ini menganggap angka (123 ...) sebagai huruf.
Nama
Mudah diperbaiki.
abo-abo
Terima kasih banyak lagi. Lain positif palsu: Ini menganggap ۹(yaitu, angka 9 India) atau ٪sebagai surat.
Nama
1
Solusi pertama Anda baik-baik saja dengan huruf-huruf Yunani (seperti ζatau α), tetapi pembaruannya tidak.
Nama
Tetapi menggabungkan keduanya adalah solusi yang lebih dekat.
Nama
2

Jika Anda sangat prihatin tentang karakter nasional dan perlakuan tepat terhadap kelas karakter Unicode, maka satu-satunya solusi yang saya dapat temukan sejauh ini adalah regexpustaka Python . Keduanya grepdan Perl(mengejutkan saya!) Tidak melakukan pekerjaan dengan benar.

Jadi, ekspresi reguler Anda setelah satu ini: \p{L}. Ini dikenal sebagai versi steno properti Unicode, versi lengkapnya adalah \p{Letter}atau bahkan p\{General_Category=Letter}. Letteritu sendiri adalah kelas komposit, tapi saya tidak akan pergi ke rincian, referensi terbaik yang bisa saya temukan pada subjek ada di sini .

Pustaka Python tidak terintegrasi ke dalam bahasa (ini adalah alternatif untuk repustaka bawaan). Jadi, Anda harus menginstalnya, misalnya:

# pip install regex

Kemudian, Anda bisa menggunakannya seperti ini:

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

Anda juga dapat meletakkan skrip ini di suatu tempat di mana Anda dapat mengaksesnya:

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

Dan panggil saja dari Emacs seperti itu (misalkan Anda menyimpan skrip ini di ~/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
sumber