C#比较包含小写文本的两个byte[]数组

3

当比较两个独立的byte[]源(数组/指针)中的单个字节值时,如何执行大小写不敏感的比较?

我有一个非常大的字节数组,其中包含我通过指针访问的字符串“haystack”,并将其与“needle”模式进行比较,但当前仅在存在完全匹配时返回。

是否可以创建包含大小写转换值的查找字典,并在比较循环中使用它,或者还有更快的方法吗?(从性能方面考虑)

编辑1:

字符串采用UTF8编码。

期望的行为是:在比较a、a;A、A;或a、A时返回true。但由于'A'在UTF8中的值为65,而'a'的值为97,因此我无法进行大小写不敏感的比较。


3
将每个数组转换成字符串,然后进行不区分大小写的比较。 - user47589
2
这取决于编码方式。你处理的是 ASCII 字符串吗? - Xiaoy312
1
字节的大小写敏感是什么意思?这些数组是否代表ASCII编码的字符串? - Lee
2
小写和大写的ASCII码有32的偏移量,因此您可以使用x == byte[x] || byte[x+32]进行比较,其中x为大写字母,如果我理解正确的话。 - Falco Alexander
1
@JKurcik 你的意思是十六进制20(=32)吗? - Falco Alexander
显示剩余10条评论
2个回答

3

byte数组转换为string,然后执行不区分大小写的比较。类似下面的示例:

bool caseInsensitiveByteArrayComparison(byte[] a, byte[] b) {
    string aString = System.Text.Encoding.UTF8.GetString(a);
    string bString = System.Text.Encoding.UTF8.GetString(b);
    return string.Equals(aString, bString, StringComparison.CurrentCultureIgnoreCase);
}

从SO无耻地偷了代码。见:

  1. 如何将UTF-8字节数组转换为字符串?
  2. 有没有C#不区分大小写的等于运算符?

3
小写字母和大写字母的ACSII和UTF8码字节表示有32(或hex20)的偏移量,因此您可以使用x == byte[x] || x == byte[x+32]来实现对x=大写字符值的比较。
编辑:
假设您确实只需要处理小写和大写的英文字母,则可以通过位运算进行速度优化,因为您可以一次处理8个字节/字符,因为它们只由第三个最重要的位不同: 'b' & 0b_1101_1111 == 'B' & 0b_1101_1111 因此,您可以按照8个字节的块处理字节数组。
void Main()
{
    byte[] a = "ASDADAGF".Select(x => (byte)(x) ).ToArray();
    byte[] b = "asdAdAGF".Select(x => (byte)(x) ).ToArray();
    bitCompared(a,b).Dump();
}

static bool bitCompared( byte[] b1, byte[]b2)
{
    UInt64 a = BitConverter.ToUInt64(b1, 0); //loop over the index
    UInt64 b = BitConverter.ToUInt64(b2, 0);
    UInt64 mask =0b_1101_1111_1101_1111_1101_1111_1101_1111_1101_1111_1101_1111_1101_1111_1101_1111;
    return (a &= mask) == (b &= mask);
}

据我所知,还有更多使用SIMD和其他低级“技巧”进行优化的方法......

1
你的意思是 x == byte[i] || x == byte[i]+32 吗?还是说这个逻辑或运算符有什么特殊作用?(没有批评的意思,我只是不太明白,如果数组下标越界或者循环到末尾会怎么样) - Cee McSharpface
2
@FalcoAlexander 这值得检查一下,以避免误报假阳性吗?(十进制中为65-122) - JKurcik
@JKurcik更新了答案,介绍了位运算,即使它们可能无法满足您的特殊需求。 - Falco Alexander
1
@FalcoAlexander 感谢你的努力哈哈,虽然我担心使用BitConverter会实例化新数组并导致巨大的性能损失。尝试在需要比较30mil字节数组的情况下模拟您的操作。我设法挤入了这个条件:*x1 != *x2 && (*x1 < 65 || *x1 > 122 || *x2 < 65 || *x2 > 122 || *x1 + 32 != *x2),它首先尝试精确匹配,然后确保x1和x2都在字母表内,然后尝试小写比较。我使用指针运行了30+万次,并在5ms以下得到了结果。感谢您指引我正确的方向! - JKurcik
1
我的例子只是为了展示如何通过二进制操作在第一步中处理8字节块。可以查看 System.Numerics.Vectors,以获取对128位和硬件加速数字类型的支持。对于字母数字字节的检查也可以在位掩码和移位级别上完成。也许编译器已经完成了这项工作,但是可以在 StackExchange 的汇编站点上查找一些非常好的提示......我非常喜欢这种低级性能优化。也许你可以使用一个新的问题来挑战它,带有优化标签和一组定义好的数据,以及一个开始的示例。 - Falco Alexander
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接