哪些unicode范围被认为是字母



我正在尝试做一些文本处理。我可以很容易地为我知道的语言写一个正则表达式(A-Z为英语),但是在希伯来语,阿拉伯语,中文等中添加一个字母就太多了。

unicode认为哪些字符范围是字母?

除了按其范围分类外,每个Unicode字符都有一个称为"一般类别"的东西。您可能希望使用以下类别:

[Lu]    Letter, Uppercase
[Ll]    Letter, Lowercase
[Lt]    Letter, Titlecase
[Lm]    Letter, Modifier
[Lo]    Letter, Other

这排除了数字、标点、符号等(它与Java的Character.isLetter使用的集合相同)。如果你的正则表达式引擎支持它,你可以用p{L}检查输入字符是否在这些类别之一。

完整的分类列表在Wikipedia上,unicode.org有更多关于p regex语法的信息。

您可能需要查看这个:Unicode字符范围,其中包含语言的范围。具体来说,没有一个通用的范围,它因语言的不同而不同,比如阿拉伯语是0600 - 06FF,希伯来语是0590 - 05FF等等。

简短回答:

  • 如果您的目标UTF-16 基本多语言平面(BMP):您有380范围。
  • 如果您的目标UTF-16补充代码点:您有648范围。

长答:

(如果你想绕过这个解释,直接跳转到代码部分)。

如果我们考虑UTF-16 基本多语言平面(BMP),码点范围从0x00000xFFFF,这意味着一些65536码点。在JavaC#等语言中,Char支持的类型

除了BMP, Unicode还支持其他平面(实际上是16个平面),以支持其他字符(不知名的语言,表情符号等),范围从0x100000x10FFFF,使用21位,这基本上是不可能使用UTF-16的两个字节。这是使用Surrogates实现的,在BMP范围内的几个代码点(低和高)将帮助我们找到BMP无法表示的字符,在一个特殊的公式中使用低和高的代理来确定目标字符。本文提供更多细节和更好的解释。

让我们把所有这些翻译成语言词汇,如C#:

BMP字符用类型Char表示,可以表示65536个字符。

为了表示其他平面的字符,我们可以使用char.ConvertFromUtf32(n)(例如n在0x0000000x00D7FF之间,0x00E0000x10FFFF之间,区间[0x00D800, 0x00DFFF]专用于代理)。更好的选择是Rune类型。Rune类似于Char,但支持Char所不能的,这意味着其他平面的代码点。

符文字符"如前所述,不属于Char范围的部分使用代理计算。换句话说,一个Rune最多可以由2个Char实例表示,参见符文。EncodeToUtf16和Rune.Utf16SequenceLength.

被认为是字母的字符范围是什么?

CharRune都有能力告诉我们一个"字符"是字母还是不是,因为它们都提供了各自的IsLetter()方法。

一个简单的解决方案是遍历Char的范围并应用Char。IsLetter方法,同样适用于Rune。有两种方法:

  1. 第一个方法CharLettersRanges获取的字母范围从065535

    public IEnumerable<(ulong from, ulong to)> CharLettersRanges()
    {
        var ranges = new List<(ulong from, ulong to)>();
        char c = default(char);
        var isLetter = false;
        ulong start = 0;
        ulong end = 0x00FFFF; // 65_535;
        var range = default((ulong from, ulong to));
        for (ulong i = start; i <= end; i++)
        {
            c = (char)i;
            if (char.IsLetter(c))
            {
                if (!isLetter)
                {
                    isLetter = true;
                    range.from = i;
                }
            }
            else
            {
                if (isLetter)
                {
                    isLetter = false;
                    range.to = i - 1;
                    ranges.Add(range);
                }
            }
        }
        return ranges;
    }
    
  2. 第二种方法RuneLettersRanges用于查找超出[ 0,65535 ]的范围(当然是通过避免代理范围),这意味着从055,295和从57,3441,114,111。(请注意,并非所有这些代码点都代表实际的字符,其中许多尚未归属)。

    public IEnumerable<(ulong from, ulong to)> RuneLettersRanges()
    {
        var ranges = new List<(ulong from, ulong to)>();
        Rune c = default(Rune);
        var isLetter = false;
        var range = default((ulong from, ulong to));
        ulong start = 0;
        ulong end = 0xD7FF; //55_295;
        for (ulong i = start; i <= end; i++)
        {
            c = (Rune)i;
            if (Rune.IsLetter(c))
            {
                if (!isLetter)
                {
                    isLetter = true;
                    range.from = i;
                }
            }
            else
            {
                if (isLetter)
                {
                    isLetter = false;
                    range.to = i - 1;
                    ranges.Add(range);
                }
            }
        }
        //Avoiding surrogates between 0xD800 and 0xDFFF
        start = 0xE000; //57_344
        end = 0x10FFFF; //1_114_111;
        for (ulong i = start; i <= end; i++)
        {
            c = (Rune)i;
            if (Rune.IsLetter(c))
            {
                if (!isLetter)
                {
                    isLetter = true;
                    range.from = i;
                }
            }
            else
            {
                if (isLetter)
                {
                    isLetter = false;
                    range.to = i - 1;
                    ranges.Add(range);
                }
            }
        }
        return ranges;
    }
    

第一个方法CharLettersRanges将返回380个范围,而第二个方法RuneLettersRanges将返回648个范围。

如果您必须选择一种方法,您可以放心地考虑容量较大的字符Rune,因为Char的380个范围包含在Rune的648个范围中。

为了好玩,你可以计算有多少字母"到现在"在Unicode系统中,通过对范围的长度求和,将得到131756个字母

最新更新