c# - 获取 "belong"到当前文化的字符列表

标签 c# .net vb.net character-encoding cultureinfo

我想创建一个字符串,其中包含当前用户预期能够在键盘上输入的所有字符。对于英语文化中的用户,这将是 26 个大写字母和 26 个小写字母、10 个十进制数字和 30 多个符号。来自其他国家的用户会有一些不同的特征。

我知道用户可以通过多种方式输入他或她的键盘上没有的字符,但我不能假设他们知道如何操作。我正在寻找一组字符,我认为具有当前文化的任何人都应该能够输入这些字符是合理的。如果该集缺少一两个特殊字符,这不是世界末日,但我希望它合理完整。

我可以通过硬编码或使用如下函数快速获取美国英语字符集:

Function GetCharacterSet() As String
    Return Enumerable.Range(32, 95).Select(Function(i) Chr(i)).ToArray
End Function

我不确定如何为其他文化可靠地做到这一点。我可以像这样编写函数:

Function GetCharacterSet() As String
    Dim chars As New List(Of Char) 
    For i As Integer = 0 To UInt16.MaxValue 
        Dim ch As Char = ChrW(i)
        If Char.IsLetterOrDigit(ch) OrElse Char.IsPunctuation(ch) OrElse ch = " "c Then 
            chars.Add(ch)
        End If
    Next
    Return chars.ToArray 
End Function

但生成的(很长的)字符串包含在任何 文化中有效的字符。有没有一种方法可以检查字符是否仅在当前 文化中是字母、数字或标点符号?

最佳答案

好吧,这有点倒退,但这是迄今为止我能用键盘布局 API 管理的最好的:

public class Api
{
    [DllImport("kernel32.dll")]
    public static extern uint GetCurrentThreadId();

    [DllImport("user32.dll")]
    public static extern IntPtr GetKeyboardLayout(uint idThread);

    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern short VkKeyScanEx(char ch, IntPtr dwhkl);
}

class Program
{
    static bool IsRepresentable(char c, IntPtr keyboardLayout)
    {
        var x = Api.VkKeyScanEx(c, keyboardLayout);
        return x != -1;
    }

    static IEnumerable<char> GetKeyboardLayoutCharacters(IntPtr keyboardLayout)
    {
        return
            Enumerable.Range(32, char.MaxValue - 32)
                .Select(n => (char)n)
                .Where(c => IsRepresentable(c, keyboardLayout));
    }

    static void Main(string[] args)
    {
        Console.OutputEncoding = Encoding.UTF8;
        var layout = Api.GetKeyboardLayout(Api.GetCurrentThreadId());
        Console.WriteLine(string.Concat(GetKeyboardLayoutCharacters(layout)));
    }
}

这实际上是搜索所有 BMP 并询问每个字符是否可以由给定的键盘布局表示。不理想,但它返回以下内容:

德语:

 !"#$%&'()*+,-./0123456789:;<=>?@
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`
abcdefghijklmnopqrstuvwxyz
{|}~§°²³´µÄÖÜßäöüẞ€

波兰语:

 !"#$%&'()*+,-./0123456789:;<=>?@
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`
abcdefghijklmnopqrstuvwxyz
{|}~ÓóĄąĆćĘꣳŃńŚśŹźŻż€

美国英语:

 !"#$%&'()*+,-./0123456789:;<=>?@
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`
abcdefghijklmnopqrstuvwxyz{|}~

美国国际 ;-):

 !"#$%&'()*+,-./0123456789:;<=>?@
ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`
abcdefghijklmnopqrstuvwxyz
{|}~¡¢£¤¥¦§¨©«¬®°²³´µ¶¹»¼½¾¿ÁÄÅÆÇÉÍÐÑÓÖ×ØÚÜÞßáäåæçéíðñóö÷øúüþ‘’€

我相当确定一定有一种方法可以实际获取给定键盘布局可以产生的字符,因为上面的列表没有考虑死键(例如美国国际实际上可以产生ÿõï 但它们不在列表中,因为无法使用 Shift、Ctrl 或 Alt 生成它们——您必须使用死键)。但作为第一个近似值,这可能已经有用了。此外,其中有些东西很奇怪,与其说是包含 U+007F(即 Del),不如说是包含 U+F000 和 U+F001。可能需要对返回列表进行额外过滤。

此方法还假定代表其语言的用户的键盘布局处于事件状态。但是,如果这仅与当前用户的语言有关,这可能是最常见的情况。

编辑:

Vb.Net 版本

Private NotInheritable Class NativeMethods
    <DllImport("user32.dll", CharSet:=CharSet.Unicode)>
    Public Shared Function VkKeyScanEx(ByVal ch As Char, ByVal dwhkl As IntPtr) As Short
    End Function
End Class

<Extension>
Public Function IsAlphabetic(ByVal sender As String,
                             ByVal culture As CultureInfo) As Boolean

    If Not CultureInfo.GetCultures(CultureTypes.InstalledWin32Cultures).Contains(culture) Then
        Throw New CultureNotFoundException(paramName:="culture", message:="Culture not installed.")

    Else
        ' Keyboard Layout Handle (HKL)
        Dim hkl As IntPtr = InputLanguage.FromCulture(culture).Handle

        Dim charList As New List(Of Char)
        For index As UShort = 0US To (UShort.MaxValue - 1US)

            Dim c As Char = Convert.ToChar(index)

            ' The check for being a letter can always be removed if symbols or numbers should be allowed, too.
            If (NativeMethods.VkKeyScanEx(c, hkl) <> -1S) AndAlso Char.IsLetterOrDigit(c) Then
                charList.Add(c)
            End If

        Next index

        For Each c As Char In sender
            If Not charList.Contains(c) Then
                Return False
            End If
        Next

        Return True

    End If

End Function

关于c# - 获取 "belong"到当前文化的字符列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29777125/

相关文章:

c# - 什么会导致 DbSet 中的持久化实体分离?

c# - ImageButton 中的回发或回调参数无效

c# - 查询数据库的数组 int

c# - 抽象属性的可访问性

c# - Fluent Security - 配置参数化 Controller 操作

c# - 使用 WMI 禁用帐户

c# - 如何在 .NET Core 2.0 中包含库

vb.net - VB.net 中的拆分

c# - 在保存到数据库之前检查类是否为新实例或至少填充一次属性

c# - 如何从连接到PC的手机发送和读取短信