C# 比较两个包含小写文本的 byte[] 数组
Posted
技术标签:
【中文标题】C# 比较两个包含小写文本的 byte[] 数组【英文标题】:C# Compare two byte[] arrays containing text as lowercase 【发布时间】:2019-05-13 21:06:24 【问题描述】:当比较来自两个单独的 byte[] 源(数组/指针)的单个字节值时,如何执行 case INSENSITIVE 比较?
我有一个非常大的字节数组,其中包含我通过指针访问的字符串的“干草堆”,我将它与“针”模式进行比较,但目前它仅在存在完全区分大小写的匹配时才返回。
是否可以创建一个包含从上到下的值的查找字典并在比较循环中使用它,还是有更快的方法? (性能方面)
编辑1:
字符串是 UTF8 编码的。
期望的行为是:在比较 a,a 时返回 true;一个,一个;或a,A。但由于 UTF8 中的 'A' 的值为 65,而 'a' 的值为 97,我无法进行不区分大小写的比较。
【问题讨论】:
将每个数组转换为字符串,然后进行不区分大小写的比较... 这取决于编码。你在处理 ascii 字符串吗? 字节区分大小写是什么意思?数组是否代表 ascii 编码的字符串? 小写和大写 ACSII 代码的偏移量为 32,因此如果我理解正确,您可以将x == byte[x] || byte[x+32]
与 x=大写进行比较
UTF8 的偏移量应该相同
【参考方案1】:
小写和大写 ACSII 和 UTF8 代码的字节表示具有 32(或 hex20)的偏移量,因此您可以实现 x == byte[x] || x == byte[x+32]
与 x=大写字符值的比较。
编辑:
假设您真的只需要处理小写和大写英文字母,您可以使用按位运算来加快速度,因为您可以一次处理 8 个字节/字符,因为它们仅在第 3 个最重要的位上有所不同:
'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);
afaik 还有更多使用 SIMD 和其他低级“黑客”进行优化的方法.....
【讨论】:
你的意思是x == byte[i] || x == byte[i]+32
,或者这应该如何与逻辑或一起工作? (没有批评,我就是不明白,indexoutofrange 和 wraparound 怎么样)
你是对的,这是一个错字,但也可以通过按位比较来完成,因为大写和小写字符 onyl 的第二个最高有效位不同!我稍后会添加,因为这甚至应该优于“正常”字节比较!
@FalcoAlexander 是否值得检查字节值是否超出字母范围以避免误报? (十进制 65-122)
@FalcoAlexander 感谢您的努力哈哈,尽管我害怕使用 BitConverter 会实例化新数组并造成巨大的性能损失。尝试在需要比较 3000 万字节数组的场景中模拟您的操作。我设法挤进了这种情况:*x1 != *x2 && (*x1 < 65 || *x1 > 122 || *x2 < 65 || *x2 > 122 || *x1 + 32 != *x2)
首先尝试完全匹配,然后确保 x1 和 x2 都在字母范围内,然后尝试小写比较。我运行了 30 多万次,使用指针的时间不到 5 毫秒。感谢您为我指明正确的方向!
我的例子只是为了表明使用二进制操作的 8 字节块可以在第一步中完成。查看System.Numerics.Vectors
以获得对128 位和硬件加速数字类型的支持。字母数字字节的检查也可以在位掩码和移位级别上完成。可能是编译器已经这样做了,但是请检查 StackExchange 的汇编器站点以获得一些非常好的提示……我非常喜欢这种低级性能优化。可能是您提出了一个带有优化标签的新问题和一组定义的数据以及一个示例开始的挑战。【参考方案2】:
将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 中窃取。见:
-
How to convert UTF-8 byte[] to string?
Is there a C# case insensitive equals operator?
【讨论】:
以上是关于C# 比较两个包含小写文本的 byte[] 数组的主要内容,如果未能解决你的问题,请参考以下文章
unity c# byte array to struct 包含数据数组