The Microsoft documentation for
public bool Binary.Equals(Binary other)
gives no indication as to whether this tests equality of reference as with objects in general or equality of value as with strings.
Can anyone clarify?
John Skeet's answer inspired me to expand it to this:
using System;
using System.Data.Linq;
public class Program
{
static void Main(string[] args)
{
Binary a = new Binary(new byte[] { 1, 2, 3 });
Binary b = new Binary(new byte[] { 1, 2, 3 });
Console.WriteLine("a.Equals(b) >>> {0}", a.Equals(b));
Console.WriteLine("a {0} == b {1} >>> {2}", a, b, a == b);
b = new Binary(new byte[] { 1, 2, 3, 4 });
Console.WriteLine("a {0} == b {1} >>> {2}",a,b, a == b);
/* a < b is not supported */
}
}
Well, a simple test suggests it is value equality:
using System;
using System.Data.Linq;
class Program {
static void Main(string[] args)
{
Binary a = new Binary(new byte[] { 1, 2, 3 });
Binary b = new Binary(new byte[] { 1, 2, 3 });
Console.WriteLine(a.Equals(b)); // Prints True
}
}
The fact that they've bothered to implement IEquatable<Binary> and override Equals(object) to start with suggests value equality semantics too... but I agree that the docs should make this clear.
It's a value comparison per Reflector...
private bool EqualsTo(Binary binary)
{
if (this != binary)
{
if (binary == null)
{
return false;
}
if (this.bytes.Length != binary.bytes.Length)
{
return false;
}
if (this.hashCode != binary.hashCode)
{
return false;
}
int index = 0;
int length = this.bytes.Length;
while (index < length)
{
if (this.bytes[index] != binary.bytes[index])
{
return false;
}
index++;
}
}
return true;
}
Reflector shows that Binary.Equals compares by real binary value, not by the reference.
Related
I know it's possible to verify Bitcoin wallet addresses with Regex (^[13][a-km-zA-HJ-NP-Z0-9]{26,33}$) - but this is not 100% accurate and allows invalid addresses to be detected as valid.
Is there publicly available C# algorithm that can verify bitcoin wallet addresses? I've been Googling for one, but couldn't find anything.
Yes, the Bitcoin-Address-Utility project is an open-source C# tool that includes this kind of verification. In particular, look at Casascius.Bitcoin.Util.Base58CheckToByteArray().
I pieced together a simple version of Casascius.Bitcoin.Util.Base58CheckToByteArray() that works with dotnet core 2.0 - The only reference is to -->Org.BouncyCastle.Crypto.Digests;
public class Validator
{
public static bool IsValidAddress(string Address)
{
byte[] hex = Base58CheckToByteArray(Address);
if (hex == null || hex.Length != 21)
return false;
else
return true;
}
public static byte[] Base58CheckToByteArray(string base58)
{
byte[] bb = Base58.ToByteArray(base58);
if (bb == null || bb.Length < 4) return null;
Sha256Digest bcsha256a = new Sha256Digest();
bcsha256a.BlockUpdate(bb, 0, bb.Length - 4);
byte[] checksum = new byte[32];
bcsha256a.DoFinal(checksum, 0);
bcsha256a.BlockUpdate(checksum, 0, 32);
bcsha256a.DoFinal(checksum, 0);
for (int i = 0; i < 4; i++)
{
if (checksum[i] != bb[bb.Length - 4 + i]) return null;
}
byte[] rv = new byte[bb.Length - 4];
Array.Copy(bb, 0, rv, 0, bb.Length - 4);
return rv;
}
}
} - borrowed from above
public class Base58
{
/// <summary>
/// Converts a base-58 string to a byte array, returning null if it wasn't valid.
/// </summary>
public static byte[] ToByteArray(string base58)
{
Org.BouncyCastle.Math.BigInteger bi2 = new Org.BouncyCastle.Math.BigInteger("0");
string b58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
foreach (char c in base58)
{
if (b58.IndexOf(c) != -1)
{
bi2 = bi2.Multiply(new Org.BouncyCastle.Math.BigInteger("58"));
bi2 = bi2.Add(new Org.BouncyCastle.Math.BigInteger(b58.IndexOf(c).ToString()));
}
else
{
return null;
}
}
byte[] bb = bi2.ToByteArrayUnsigned();
// interpret leading '1's as leading zero bytes
foreach (char c in base58)
{
if (c != '1') break;
byte[] bbb = new byte[bb.Length + 1];
Array.Copy(bb, 0, bbb, 1, bb.Length);
bb = bbb;
}
return bb;
}
public static string FromByteArray(byte[] ba)
{
Org.BouncyCastle.Math.BigInteger addrremain = new Org.BouncyCastle.Math.BigInteger(1, ba);
Org.BouncyCastle.Math.BigInteger big0 = new Org.BouncyCastle.Math.BigInteger("0");
Org.BouncyCastle.Math.BigInteger big58 = new Org.BouncyCastle.Math.BigInteger("58");
string b58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
string rv = "";
while (addrremain.CompareTo(big0) > 0)
{
int d = Convert.ToInt32(addrremain.Mod(big58).ToString());
addrremain = addrremain.Divide(big58);
rv = b58.Substring(d, 1) + rv;
}
// handle leading zeroes
foreach (byte b in ba)
{
if (b != 0) break;
rv = "1" + rv;
}
return rv;
}
}
} - Tests
[TestClass]
public class ValidatorTests
{
[TestMethod]
public void IsValidAddress_Test_AbnCoin()
{
var Address = "1QF4NgxgF86SH4dizN4JPHMprWBHbKdSmJ";
Assert.IsTrue(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_Test_BitCoin()
{
var Address = "1QF4NgxgF86SH4dizN4JPHMprWBHbKdSmJ";
Assert.IsTrue(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_Test_BitCoinTestnet()
{
var Address = "mpMwtvqaLQ4rCJsnoceAoLShKb4inV8uUi";
Assert.IsTrue(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_Test_BitCoinGold()
{
var Address = "GRiDm3LEjXAMMJhWaYqN8nSjuU7PSqZMUe";
Assert.IsTrue(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_Test_Dash()
{
var Address = "Xb9Edf28eYR9RRDwj7MBBVBc5vgGgT2vLV";
Assert.IsTrue(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_Test_Litecoin()
{
var Address = "LUdpZosHDP3M97ZSfvj3p1qygNFMNpXBr3";
Assert.IsTrue(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_Test_False_TooShort()
{
var Address = "1QF4NgxgF86SH4dizN4JPHMprWBHbKdSm";
Assert.IsFalse(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_Test_False_TooLong()
{
var Address = "1QF4NgxgF86SH4dizN4JPHMprWBHbKdSmJS";
Assert.IsFalse(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_Test_False_BadChecksum()
{
var Address = "1QF5NgxgF86SH4dizN4JPHMprWBHbKdSmJ";
Assert.IsFalse(Validator.IsValidAddress(Address));
}
[TestMethod]
public void IsValidAddress_False_NotBase58()
{
var Address = "lQF4NgxgF86SH4dizN4JPHMprWBHbKdSmJ";
Assert.IsFalse(Validator.IsValidAddress(Address));
}
}
}
tl;dr:
Had the same problem, therefore built something that suits my (and hopefully your) needs:
https://github.com/Sofoca/CoinUtils
My specific requirements were…
Support for Bitcoin and Litecoin (and in the future probably other similar Altcoins)
Support for all address types (P2SH and P2PKH) and encodings (Base58 and Bech32)
Preferably no external (think NuGet) dependencies
While none of the above mentioned alternatives met all those I took some inspiration from previous answers and referenced projects. Thanks for that!
Hope this helps those searching for a complete yet lightweight solution to this problem.
Here is Util.Bitcoin Git repository that contains only code needed for offline verification of BTC Wallet address.
Code is extracted from that Bitcoin-Address-Utility project referenced by other answer, but this repository contains necessary DLLs plus it is class project and not Windows app, so it can be directly referenced.
In Java I can pass a Scanner a string and then I can do handy things like, scanner.hasNext() or scanner.nextInt(), scanner.nextDouble() etc.
This allows some pretty clean code for parsing a string that contains rows of numbers.
How is this done in C# land?
If you had a string that say had:
"0 0 1 22 39 0 0 1 2 33 33"
In Java I would pass that to a scanner and do a
while(scanner.hasNext())
myArray[i++] = scanner.nextInt();
Or something very similar. What is the C#' ish way to do this?
I'm going to add this as a separate answer because it's quite distinct from the answer I already gave. Here's how you could start creating your own Scanner class:
class Scanner : System.IO.StringReader
{
string currentWord;
public Scanner(string source) : base(source)
{
readNextWord();
}
private void readNextWord()
{
System.Text.StringBuilder sb = new StringBuilder();
char nextChar;
int next;
do
{
next = this.Read();
if (next < 0)
break;
nextChar = (char)next;
if (char.IsWhiteSpace(nextChar))
break;
sb.Append(nextChar);
} while (true);
while((this.Peek() >= 0) && (char.IsWhiteSpace((char)this.Peek())))
this.Read();
if (sb.Length > 0)
currentWord = sb.ToString();
else
currentWord = null;
}
public bool hasNextInt()
{
if (currentWord == null)
return false;
int dummy;
return int.TryParse(currentWord, out dummy);
}
public int nextInt()
{
try
{
return int.Parse(currentWord);
}
finally
{
readNextWord();
}
}
public bool hasNextDouble()
{
if (currentWord == null)
return false;
double dummy;
return double.TryParse(currentWord, out dummy);
}
public double nextDouble()
{
try
{
return double.Parse(currentWord);
}
finally
{
readNextWord();
}
}
public bool hasNext()
{
return currentWord != null;
}
}
Using part of the answers already given, I've created a StringReader that can extract Enum and any data type that implements IConvertible.
Usage
using(var reader = new PacketReader("1 23 ErrorOk StringValue 15.22")
{
var index = reader.ReadNext<int>();
var count = reader.ReadNext<int>();
var result = reader.ReadNext<ErrorEnum>();
var data = reader.ReadNext<string>();
var responseTime = reader.ReadNext<double>();
}
Implementation
public class PacketReader : StringReader
{
public PacketReader(string s)
: base(s)
{
}
public T ReadNext<T>() where T : IConvertible
{
var sb = new StringBuilder();
do
{
var current = Read();
if (current < 0)
break;
sb.Append((char)current);
var next = (char)Peek();
if (char.IsWhiteSpace(next))
break;
} while (true);
var value = sb.ToString();
var type = typeof(T);
if (type.IsEnum)
return (T)Enum.Parse(type, value);
return (T)((IConvertible)value).ToType(typeof(T), System.Globalization.CultureInfo.CurrentCulture);
}
}
While this isn't the exact same fundamental concept, what you're looking for can be done with this lambda expression:
string foo = "0 0 1 22 39 0 0 1 2 33 33";
int[] data = foo.Split(' ').Select(p => int.Parse(p)).ToArray();
What this does is first Split the string, using a space as a delimiter. The Select function then allows you to specify an alias for a given member in the array (which I referred to as 'p' in this example), then perform an operation on that member to give a final result. The ToArray() call then turns this abstract enumerable class into a concrete array.
So in this end, this splits the string, then converts each element into an int and populates an int[] with the resulting values.
To my knowledge, there are no built in classes in the framework for doing this. You would have to roll your own.
That would not be too hard. A nice C# version might implement IEnumerable so you could say:
var scanner = new Scanner<int>(yourString);
foreach(int n in scanner)
; // your code
To get as close as possible to your syntax, this'll work if you're only interested in one type ("int" in the example):
static void Main(string[] args)
{
if (args.Length == 0) { args = new string[] { "3", "43", "6" }; }
IEnumerator<int> scanner = (from arg in args select int.Parse(arg)).GetEnumerator();
while (scanner.MoveNext())
{
Console.Write("{0} ", scanner.Current);
}
}
Here's an even more whiz-bang version that allows you to access any type that is supported by string's IConvertible implementation:
static void Main(string[] args)
{
if (args.Length == 0) { args = new string[] { "3", "43", "6" }; }
var scanner = args.Select<string, Func<Type, Object>>((string s) => {
return (Type t) =>
((IConvertible)s).ToType(t, System.Globalization.CultureInfo.InvariantCulture);
}).GetEnumerator();
while (scanner.MoveNext())
{
Console.Write("{0} ", scanner.Current(typeof(int)));
}
}
Just pass a different type to the "typeof" operator in the while loop to choose the type.
These both require the latest versions of C# and the .NET framework.
You could use linq to accomplish this like so:
string text = "0 0 1 22 39 0 0 1 2 33 33";
text.Where(i => char.IsNumber(i)).Write(); // do somthing usefull here...
I would do this in one of a couple ways depending on whether 1) you are using the latest .NET framework with LINQ support and 2) you know the values are valid integers. Here's a function to demonstrate both:
int[] ParseIntArray(string input, bool validateRequired)
{
if (validateRequired)
{
string[] split = input.Split();
List<int> result = new List<int>(split.Length);
int parsed;
for (int inputIdx = 0; inputIdx < split.Length; inputIdx++)
{
if (int.TryParse(split[inputIdx], out parsed))
result.Add(parsed);
}
return result.ToArray();
}
else
return (from i in input.Split()
select int.Parse(i)).ToArray();
}
Based on comments in other answer(s), I assume you need the validation. After reading those comments, I think the closest thing you'll get is int.TryParse and double.TryParse, which is kind of a combination of hasNextInt and nextInt (or a combination of hasNextDouble and nextDouble).
I would like to choose the third element from an enum containing three elements while knowing which two I have already chosen. What is the most effcient way of comparing enums?
EDIT:
So far I have come up with the following:
Drawable.Row alternateChoice = (Drawable.Row)ExtensionMethods.Extensions.DefaultChoice(new List<int>() { (int)chosenEnum1, (int)chosenEnum2 }, new List<int>() { 0, 1, 2 });
Drawable.Row is the enum, the first list is what has already been chosen, and the second list contains the possible choices. The definition of DefaultChoice follows. I am aware it has quadratic time-complexity which is why I'm asking for a better solution:
public static int DefaultChoice(List<int> chosen, List<int> choices)
{
bool found = false;
foreach (int choice in choices)
{
foreach (int chosenInt in chosen)
{
if (chosenInt == choice)
{
found = true;
break;
}
}
if (!found)
{
return choice;
}
found = false;
}
return -1;
}
Try this:
List<MyEnum> selectedValues = new List<MyEnum>();
selectedValues.Add(MyEnum.firstValue); // Add selected value
selectedValues.Add(MyEnum.secondValue); // Add selected value
List<MyEnum> valuesLeftOver = Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToList();
valuesLeftOver = valuesLeftOver.Except(selectedValues).ToList<MyEnum>(); // This will result in the remaining items (third item) being in valuesLeftOver list.
Short and simple code.
Try not to worry about efficiency too much. Optimization algorithms are so powerful these days that you will probably get same assembly code doing this rather than trying to do it manually.
[Flags]
public enum NumberEnum : byte
{
None = 0,
One = 1,
Two = 2,
Three = 4
};
public string GetRemainingEnumItem(NumberEnum filterFlags = 0)
{
if (((filterFlags & NumberEnum.One) == NumberEnum.One) && ((filterFlags & NumberEnum.Two) == NumberEnum.Two))
{
//1 & 2 are selected so item 3 is what you want
}
if (((filterFlags & NumberEnum.One) == NumberEnum.One) && ((filterFlags & NumberEnum.Three) == NumberEnum.Three))
{
//1 & 3 are selected so item 2 is what you want
}
if (((filterFlags & NumberEnum.Three) == NumberEnum.Three) && ((filterFlags & NumberEnum.Two) == NumberEnum.Two))
{
//2 & 3 are selected so item 1 is what you want
}
}
This is how you call it:
var testVal = NumberEnum.One | NumberEnum.Two;
var resultWillEqual3 = GetRemainingEnumItem(testVal);
You might like to try this approach...
public enum Marx {chico, groucho, harpo};
public Marx OtherOne(Marx x, Marx y)
{
return (Marx)((int)Marx.chico + (int)Marx.groucho + (int)Marx.harpo - (int)x - (int)y);
} // OtherOne
// ...
Marx a = Marx.harpo;
Marx b = Marx.chico;
Marx other = OtherOne(a, b); // picks groucho
This may be of use if you are using an enum marked as [Flags]...
public class Enums2
{
[Flags] public enum Bits {none = 0, aBit = 1, bBit = 2, cBit = 4, dBit = 8};
public static readonly Bits allBits;
static Enums2()
{
allBits = Bits.none;
foreach (Bits b in Enum.GetValues(typeof(Bits)))
{
allBits |= b;
}
} // static ctor
public static Bits OtherBits(Bits x)
// Returns all the Bits not on in x
{
return x ^ allBits;
} // OtherBits
// ...
Bits someBits = Bits.aBit | Bits.dBit;
Bits missingBits = OtherBits(someBits); // gives bBit and cBit
} // Enums2
This will probably be an extremely simple question. I'm simply trying to remove duplicate byte[]s from a collection.
Since the default behaviour is to compare references, I tought that creating an IEqualityComparer would work, but it doesn't.
I've tried using a HashSet and LINQ's Distinct().
Sample code:
using System;
using System.Collections.Generic;
using System.Linq;
namespace cstest
{
class Program
{
static void Main(string[] args)
{
var l = new List<byte[]>();
l.Add(new byte[] { 5, 6, 7 });
l.Add(new byte[] { 5, 6, 7 });
Console.WriteLine(l.Distinct(new ByteArrayEqualityComparer()).Count());
Console.ReadKey();
}
}
class ByteArrayEqualityComparer : IEqualityComparer<byte[]>
{
public bool Equals(byte[] x, byte[] y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(byte[] obj)
{
return obj.GetHashCode();
}
}
}
Output:
2
The GetHashCode will be used by Distinct, and won't work "as is"; try something like:
int result = 13 * obj.Length;
for(int i = 0 ; i < obj.Length ; i++) {
result = (17 * result) + obj[i];
}
return result;
which should provide the necessary equality conditions for hash-codes.
Personally, I would also unroll the equality test for performance:
if(ReferenceEquals(x,y)) return true;
if(x == null || y == null) return false;
if(x.Length != y.Length) return false;
for(int i = 0 ; i < x.Length; i++) {
if(x[i] != y[i]) return false;
}
return true;
In Java I can pass a Scanner a string and then I can do handy things like, scanner.hasNext() or scanner.nextInt(), scanner.nextDouble() etc.
This allows some pretty clean code for parsing a string that contains rows of numbers.
How is this done in C# land?
If you had a string that say had:
"0 0 1 22 39 0 0 1 2 33 33"
In Java I would pass that to a scanner and do a
while(scanner.hasNext())
myArray[i++] = scanner.nextInt();
Or something very similar. What is the C#' ish way to do this?
I'm going to add this as a separate answer because it's quite distinct from the answer I already gave. Here's how you could start creating your own Scanner class:
class Scanner : System.IO.StringReader
{
string currentWord;
public Scanner(string source) : base(source)
{
readNextWord();
}
private void readNextWord()
{
System.Text.StringBuilder sb = new StringBuilder();
char nextChar;
int next;
do
{
next = this.Read();
if (next < 0)
break;
nextChar = (char)next;
if (char.IsWhiteSpace(nextChar))
break;
sb.Append(nextChar);
} while (true);
while((this.Peek() >= 0) && (char.IsWhiteSpace((char)this.Peek())))
this.Read();
if (sb.Length > 0)
currentWord = sb.ToString();
else
currentWord = null;
}
public bool hasNextInt()
{
if (currentWord == null)
return false;
int dummy;
return int.TryParse(currentWord, out dummy);
}
public int nextInt()
{
try
{
return int.Parse(currentWord);
}
finally
{
readNextWord();
}
}
public bool hasNextDouble()
{
if (currentWord == null)
return false;
double dummy;
return double.TryParse(currentWord, out dummy);
}
public double nextDouble()
{
try
{
return double.Parse(currentWord);
}
finally
{
readNextWord();
}
}
public bool hasNext()
{
return currentWord != null;
}
}
Using part of the answers already given, I've created a StringReader that can extract Enum and any data type that implements IConvertible.
Usage
using(var reader = new PacketReader("1 23 ErrorOk StringValue 15.22")
{
var index = reader.ReadNext<int>();
var count = reader.ReadNext<int>();
var result = reader.ReadNext<ErrorEnum>();
var data = reader.ReadNext<string>();
var responseTime = reader.ReadNext<double>();
}
Implementation
public class PacketReader : StringReader
{
public PacketReader(string s)
: base(s)
{
}
public T ReadNext<T>() where T : IConvertible
{
var sb = new StringBuilder();
do
{
var current = Read();
if (current < 0)
break;
sb.Append((char)current);
var next = (char)Peek();
if (char.IsWhiteSpace(next))
break;
} while (true);
var value = sb.ToString();
var type = typeof(T);
if (type.IsEnum)
return (T)Enum.Parse(type, value);
return (T)((IConvertible)value).ToType(typeof(T), System.Globalization.CultureInfo.CurrentCulture);
}
}
While this isn't the exact same fundamental concept, what you're looking for can be done with this lambda expression:
string foo = "0 0 1 22 39 0 0 1 2 33 33";
int[] data = foo.Split(' ').Select(p => int.Parse(p)).ToArray();
What this does is first Split the string, using a space as a delimiter. The Select function then allows you to specify an alias for a given member in the array (which I referred to as 'p' in this example), then perform an operation on that member to give a final result. The ToArray() call then turns this abstract enumerable class into a concrete array.
So in this end, this splits the string, then converts each element into an int and populates an int[] with the resulting values.
To my knowledge, there are no built in classes in the framework for doing this. You would have to roll your own.
That would not be too hard. A nice C# version might implement IEnumerable so you could say:
var scanner = new Scanner<int>(yourString);
foreach(int n in scanner)
; // your code
To get as close as possible to your syntax, this'll work if you're only interested in one type ("int" in the example):
static void Main(string[] args)
{
if (args.Length == 0) { args = new string[] { "3", "43", "6" }; }
IEnumerator<int> scanner = (from arg in args select int.Parse(arg)).GetEnumerator();
while (scanner.MoveNext())
{
Console.Write("{0} ", scanner.Current);
}
}
Here's an even more whiz-bang version that allows you to access any type that is supported by string's IConvertible implementation:
static void Main(string[] args)
{
if (args.Length == 0) { args = new string[] { "3", "43", "6" }; }
var scanner = args.Select<string, Func<Type, Object>>((string s) => {
return (Type t) =>
((IConvertible)s).ToType(t, System.Globalization.CultureInfo.InvariantCulture);
}).GetEnumerator();
while (scanner.MoveNext())
{
Console.Write("{0} ", scanner.Current(typeof(int)));
}
}
Just pass a different type to the "typeof" operator in the while loop to choose the type.
These both require the latest versions of C# and the .NET framework.
You could use linq to accomplish this like so:
string text = "0 0 1 22 39 0 0 1 2 33 33";
text.Where(i => char.IsNumber(i)).Write(); // do somthing usefull here...
I would do this in one of a couple ways depending on whether 1) you are using the latest .NET framework with LINQ support and 2) you know the values are valid integers. Here's a function to demonstrate both:
int[] ParseIntArray(string input, bool validateRequired)
{
if (validateRequired)
{
string[] split = input.Split();
List<int> result = new List<int>(split.Length);
int parsed;
for (int inputIdx = 0; inputIdx < split.Length; inputIdx++)
{
if (int.TryParse(split[inputIdx], out parsed))
result.Add(parsed);
}
return result.ToArray();
}
else
return (from i in input.Split()
select int.Parse(i)).ToArray();
}
Based on comments in other answer(s), I assume you need the validation. After reading those comments, I think the closest thing you'll get is int.TryParse and double.TryParse, which is kind of a combination of hasNextInt and nextInt (or a combination of hasNextDouble and nextDouble).