C#中二进制值之间的异或运算
Xor operation between binary values in C#
我的问题是我有一个二进制字符串列表,如下所示:
list=<"1111","1010","1010","0011">
和二进制值 st1=1010 的输入字符串。我想在 :
之间进行 Xor
st3=st1 Xor list<0>
然后:
st3=st3 Xor list<1>
st3=st3Xor list <2>;
st3=st3 Xor list <3>;
其中操作将是 st1 Xor 与键列表中的第一个键和结果 Xor 与键列表中的第二个键和结果 Xor 与键列表中的第三个键等等。任何人都可以帮助我吗?
我试过这段代码,但它没有像我预期的那样工作:
foreach (string k in keys)
{
string st1 = textBox1.text;
string st2 = k;
string st3;
st3 = "";
//i wanted to make the length of both strings st1 and st2 equal
//here if the length of st1 greater than st2
if (st1.Length > st2.Length)
{
int n = st1.Length - st2.Length;
string pad = "";
for (int j = 1; j <= n; j++)
{ pad += 0; }
string recover = pad.ToString() + st2;
//this is my Xor operation that i made for string values
for (int counter = 0; counter < st1.Length; counter++)
{
if (st1[counter] != recover[counter])
{
st3 = st3 + '1';
}
else
{ st3 = st3 + '0'; }
}
listBox4.Items.Add("Xor :" + st3.ToString());
}
//here if st1 is less than st2
else if (st1.Length < st2.Length)
{
int nn = st2.Length - st1.Length;
string ppad = "";
for (int j = 1; j <= nn; j++)
{
ppad += 0;
}
string recover = ppad.ToString() + st1;
for (int counter = 0; counter < st2.Length; counter++)
{
if (st2[counter] != recover[counter])
{
st3 = st3 + '1';
}
else
{ st3 = st3 + '0'; }
}
listBox4.Items.Add("Xor :" + st3.ToString());}
//here if st1 equal st2
else
{
for (int counter = 0; counter < st1.Length; counter++)
{
if (st1[counter] != st2[counter])
{
st3 = st3 + '1';
}
else
{ st3 = st3 + '0'; }
}
listBox4.Items.Add("Xor :" + st3.ToString());
}
}
出乎我意料的结果是:
这是一种方法(任意长度的二进制字符串):
- 将字符串转换回
整数 BigIntegers,这样我们就可以实际使用现有的按位异或运算符(^
)。
- 使用 LINQ 的 Aggregate 将种子值 (st1) 与转换后的列表进行 Xor 连续左折叠。
因为你似乎只对最低的 4 位感兴趣,所以我应用了一个掩码,尽管如果你所有的数字都是严格的 4 位,这实际上不是必需的(因为 0 Xor 0 保留0)
您可以使用 Convert.ToString(x, 2)
将 int 转换回二进制字符串,然后使用 PadLeft 替换任何缺失的前导零。
Edit - OP 已将问题从示例 4 位数更改为现在要求使用任意长度的二进制字符串。这种方法仍然有效,但我们需要使用 BigInteger
(它仍然有一个 XOR
^ 运算符),但我们需要帮助程序来解析和格式化二进制字符串,因为它们没有内置到 BigInteger
。 BitMask 和填充也已被删除,因为字符串的长度不是固定的 - 结果最多有 1 个前导零:
var list = new List<string>{"10101010101010101101","1101010101010101011",
"1110111111010101101","11111111111111111111111111","10101010110101010101"};
var listNum = list.Select(l => BinaryStringToBigInteger(l));
var st1 = "000000001";
var seedNumber = BinaryStringToBigInteger(st1);
var chainedXors = listNum.Aggregate(seedNumber, (prev, next) => prev ^ next);
// Back to binary representation of the string
var resultString = chainedXors.ToBinaryString();
并且由于没有对 BigIntegers 与二进制字符串之间的本机支持,因此您需要一个转换助手,例如 Douglas's one here:
BigInteger BinaryStringToBigInteger(string binString)
{
return binString.Aggregate(BigInteger.Zero, (prev, next) => prev * 2 + next - '0');
}
而逆向运算,ToBinaryString
来自于此helper。
32 位整数答案
如果二进制字符串为 32 位或更少,则存在更简单的解决方案,因为存在开箱即用的二进制字符串转换。同样的方法应该适用于 64 位 longs。
var list = new List<string>{"1111","1010","1010","0011","0011"};
var listNum = list.Select(l => Convert.ToInt32(l, 2));
// If you only want the last 4 bits. Change this to include as many bits as needed.
var bitMask = Convert.ToInt32("00000000000000000000000000001111", 2);
var st1 = "1010";
var someNum = Convert.ToInt32(st1, 2);
var chainedXors = listNum.Aggregate(someNum, (prev, next) => prev ^ next);
// If you need the result back as a 4 bit binary-string, zero padded
var resultString = Convert.ToString(chainedXors & bitMask, 2)
.PadLeft(4, '0');
这里有一个 Xor
方法供您参考:
public static string Xor(string s1, string s2) {
// find the length of the longest of the two strings
int longest = Math.Max(s1.Length, s2.Length);
// pad both strings to that length. You don't need to write the padding
// logic yourself! There is already a method that does that!
string first = s1.PadLeft(longest, '0');
string second = s2.PadLeft(longest, '0');
// Enumerable.Zip takes two sequences (in this case sequences of char, aka strings)
// and lets you transform each element in the sequences. Here what
// I did was check if the two chars are not equal, in which case
// I transform the two elements to a 1, 0 otherwise
return string.Join("", Enumerable.Zip(first, second, (x, y) => x != y ? '1' : '0'));
}
你可以这样使用它:
Xor("1111", "1010") // 0101
试试这个代码:
static void Main(string[] args)
{
List<string> list = new List<string> { "1111", "1010", "1010", "0011" };
string st1 = "1010";
foreach (string item in list)
{
st1 = XorBins(st1, item);
Console.WriteLine(st1);
}
Console.ReadKey();
}
private static string XorBins(string bin1, string bin2)
{
int len = Math.Max(bin1.Length, bin2.Length);
string res = "";
bin1 = bin1.PadLeft(len, '0');
bin2 = bin2.PadLeft(len, '0');
for (int i = 0; i < len; i++)
res += bin1[i] == bin2[i] ? '0' : '1';
return res;
}
我的问题是我有一个二进制字符串列表,如下所示:
list=<"1111","1010","1010","0011">
和二进制值 st1=1010 的输入字符串。我想在 :
之间进行 Xorst3=st1 Xor list<0>
然后:
st3=st3 Xor list<1>
st3=st3Xor list <2>;
st3=st3 Xor list <3>;
其中操作将是 st1 Xor 与键列表中的第一个键和结果 Xor 与键列表中的第二个键和结果 Xor 与键列表中的第三个键等等。任何人都可以帮助我吗? 我试过这段代码,但它没有像我预期的那样工作:
foreach (string k in keys)
{
string st1 = textBox1.text;
string st2 = k;
string st3;
st3 = "";
//i wanted to make the length of both strings st1 and st2 equal
//here if the length of st1 greater than st2
if (st1.Length > st2.Length)
{
int n = st1.Length - st2.Length;
string pad = "";
for (int j = 1; j <= n; j++)
{ pad += 0; }
string recover = pad.ToString() + st2;
//this is my Xor operation that i made for string values
for (int counter = 0; counter < st1.Length; counter++)
{
if (st1[counter] != recover[counter])
{
st3 = st3 + '1';
}
else
{ st3 = st3 + '0'; }
}
listBox4.Items.Add("Xor :" + st3.ToString());
}
//here if st1 is less than st2
else if (st1.Length < st2.Length)
{
int nn = st2.Length - st1.Length;
string ppad = "";
for (int j = 1; j <= nn; j++)
{
ppad += 0;
}
string recover = ppad.ToString() + st1;
for (int counter = 0; counter < st2.Length; counter++)
{
if (st2[counter] != recover[counter])
{
st3 = st3 + '1';
}
else
{ st3 = st3 + '0'; }
}
listBox4.Items.Add("Xor :" + st3.ToString());}
//here if st1 equal st2
else
{
for (int counter = 0; counter < st1.Length; counter++)
{
if (st1[counter] != st2[counter])
{
st3 = st3 + '1';
}
else
{ st3 = st3 + '0'; }
}
listBox4.Items.Add("Xor :" + st3.ToString());
}
}
出乎我意料的结果是:
这是一种方法(任意长度的二进制字符串):
- 将字符串转换回
整数BigIntegers,这样我们就可以实际使用现有的按位异或运算符(^
)。 - 使用 LINQ 的 Aggregate 将种子值 (st1) 与转换后的列表进行 Xor 连续左折叠。
因为你似乎只对最低的 4 位感兴趣,所以我应用了一个掩码,尽管如果你所有的数字都是严格的 4 位,这实际上不是必需的(因为 0 Xor 0 保留0)您可以使用Convert.ToString(x, 2)
将 int 转换回二进制字符串,然后使用 PadLeft 替换任何缺失的前导零。
Edit - OP 已将问题从示例 4 位数更改为现在要求使用任意长度的二进制字符串。这种方法仍然有效,但我们需要使用 BigInteger
(它仍然有一个 XOR
^ 运算符),但我们需要帮助程序来解析和格式化二进制字符串,因为它们没有内置到 BigInteger
。 BitMask 和填充也已被删除,因为字符串的长度不是固定的 - 结果最多有 1 个前导零:
var list = new List<string>{"10101010101010101101","1101010101010101011",
"1110111111010101101","11111111111111111111111111","10101010110101010101"};
var listNum = list.Select(l => BinaryStringToBigInteger(l));
var st1 = "000000001";
var seedNumber = BinaryStringToBigInteger(st1);
var chainedXors = listNum.Aggregate(seedNumber, (prev, next) => prev ^ next);
// Back to binary representation of the string
var resultString = chainedXors.ToBinaryString();
并且由于没有对 BigIntegers 与二进制字符串之间的本机支持,因此您需要一个转换助手,例如 Douglas's one here:
BigInteger BinaryStringToBigInteger(string binString)
{
return binString.Aggregate(BigInteger.Zero, (prev, next) => prev * 2 + next - '0');
}
而逆向运算,ToBinaryString
来自于此helper。
32 位整数答案
如果二进制字符串为 32 位或更少,则存在更简单的解决方案,因为存在开箱即用的二进制字符串转换。同样的方法应该适用于 64 位 longs。
var list = new List<string>{"1111","1010","1010","0011","0011"};
var listNum = list.Select(l => Convert.ToInt32(l, 2));
// If you only want the last 4 bits. Change this to include as many bits as needed.
var bitMask = Convert.ToInt32("00000000000000000000000000001111", 2);
var st1 = "1010";
var someNum = Convert.ToInt32(st1, 2);
var chainedXors = listNum.Aggregate(someNum, (prev, next) => prev ^ next);
// If you need the result back as a 4 bit binary-string, zero padded
var resultString = Convert.ToString(chainedXors & bitMask, 2)
.PadLeft(4, '0');
这里有一个 Xor
方法供您参考:
public static string Xor(string s1, string s2) {
// find the length of the longest of the two strings
int longest = Math.Max(s1.Length, s2.Length);
// pad both strings to that length. You don't need to write the padding
// logic yourself! There is already a method that does that!
string first = s1.PadLeft(longest, '0');
string second = s2.PadLeft(longest, '0');
// Enumerable.Zip takes two sequences (in this case sequences of char, aka strings)
// and lets you transform each element in the sequences. Here what
// I did was check if the two chars are not equal, in which case
// I transform the two elements to a 1, 0 otherwise
return string.Join("", Enumerable.Zip(first, second, (x, y) => x != y ? '1' : '0'));
}
你可以这样使用它:
Xor("1111", "1010") // 0101
试试这个代码:
static void Main(string[] args)
{
List<string> list = new List<string> { "1111", "1010", "1010", "0011" };
string st1 = "1010";
foreach (string item in list)
{
st1 = XorBins(st1, item);
Console.WriteLine(st1);
}
Console.ReadKey();
}
private static string XorBins(string bin1, string bin2)
{
int len = Math.Max(bin1.Length, bin2.Length);
string res = "";
bin1 = bin1.PadLeft(len, '0');
bin2 = bin2.PadLeft(len, '0');
for (int i = 0; i < len; i++)
res += bin1[i] == bin2[i] ? '0' : '1';
return res;
}