【问题标题】:Xor operation between binary values in C#C#中二进制值之间的异或运算
【发布时间】:2018-06-07 05:50:25
【问题描述】:

我的问题是我有一个二进制字符串列表,如下所示:

list=

和一个二进制值 st1=1010 的输入字符串。我想异或:

st3=st1 异或列表

然后:

st3=st3 异或列表

st3=st3Xor 列表 ;

st3=st3 异或列表;

其中操作将是 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()); 
        }
            }

我没想到的结果是:

【问题讨论】:

  • 到目前为止你尝试了什么?
  • 你考虑过二进制语法 0b1010 吗?
  • 我编辑并放置了我尝试过的代码,你能看到它并帮助我@Tobias

标签: c# xor


【解决方案1】:

这是一种方法(任意长度的二进制字符串):

  • 将字符串转换回整数 BigIntegers,这样我们就可以真正得到现有按位异或运算符的实用性(^)。
  • 使用 LINQ 的 Aggregate 将种子值 (st1) 与使用 Xor 转换的列表连续左折叠。
  • 由于您似乎只对最低 4 位感兴趣,因此我应用了掩码,尽管如果您的所有数字都是严格的 4 位,这实际上不是必需的(因为 0 Xor 0 保持 0)删除>
  • 您可以使用 Convert.ToString(x, 2) 将 int 转换回二进制字符串,然后使用 PadLeft 替换任何丢失的前导零。

编辑 - 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 位长度。

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');

【讨论】:

  • 它对我没有帮助,我有长长度大小的二进制值,而且我想要二进制结果你能看到我现在所做的编辑吗!
  • 你的字符串是固定大小的吗?如果有,有多少位?我们可以将上述内容调整为任意长度的位,因为即使BigInteger 也有一个按位异或运算符。
  • 不,我的字符串不是固定大小的,它是由将 ASCII 转换为二进制产生的非常长的二进制值
【解决方案2】:

试试这个代码:

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;
}

【讨论】:

  • 不,不是我的意思,我想:1010 Xor 1111 Xor 1010 Xor 1010 Xor 0011
  • 非常感谢你解决了我的问题祝你好运
  • 您能否反转操作,即当我对列表中的相同键进行异或运算时,它会返回 string1,当我反转操作时,我的 pad left 有问题@Michal Turczyn
  • @safaa 不明白你在做什么,你能说清楚点吗?
  • 你给我的代码在密钥列表和 st1 之间进行异或 (result =st1 XOR 密钥列表),你能给我相反的过程,所以我得到 st1 的增益 where (st1=result XOR key列表),因为当我尝试时,我遇到了零填充问题,我无法再次正确地获得 st1 @Michal Turczyn
【解决方案3】:

这里有一个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

【讨论】:

  • 题外话,Enumerable.Zip 的名字总是让我头疼,因为它的名字并不能准确地反映它的操作。 A zipper alternates between left and right,这让我期望Enumerable.Zip(listofletters, listofnumbers) 应该返回A,1,B,2,C,3,D,4,...,而不是A1,B2,C3,D4,...
  • @Flater 是的,我也这么认为...我认为它会给我一个IEnumerable&lt;Tuple&lt;TFirst, TSecond&gt;&gt;
  • 这与将两个列表交错仍然不同,您的期望仍然将项目放在一起:) 我的部分期望可能是语言习惯:在荷兰语中,合并流量被称为“拉上拉链” (ritsen),正是因为cars are supposed to alternate between (source) lanes when merging into a (target) lane。但我确实觉得即使没有增加交通环境; Zip 方法命名后的拉链仍然与实际的 Zip 方法冲突。
  • @Flater 虽然您的观点是 zip 是配对数据,而不是实际交错数据,但 zip 一词在 many FP languages 中广泛使用 - 包括 Haskell、Scala 和 F#。 LINQ 的.Zip 含义相同。
  • @StuartLC 好点。我还没有想到其他语言。
猜你喜欢
  • 2014-08-13
  • 1970-01-01
  • 2014-05-04
  • 2013-06-26
  • 1970-01-01
  • 2021-04-22
  • 2021-07-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多