/// <summary> /// Parses separated decimal bytes from a string. /// </summary> /// <param name="s">A string containing delimited decimal integer numbers.</param> /// <param name="separator">A separator delimiting the values.</param> /// <returns>A byte array containing the decimal values as bytes.</returns> /// <exception cref="ArgumentNullException"><paramref name="s"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentException"><paramref name="separator"/> is <see langword="null"/> or empty.</exception> /// <exception cref="FormatException"><paramref name="s"/> is not of the correct format.</exception> /// <exception cref="OverflowException">A value in <paramref name="s"/> does not fit in the range of a <see cref="byte">byte</see> value.</exception> public static byte[] ParseDecimalBytes(this string s, string separator) { if (s == null) { Throw.ArgumentNullException(Argument.s); } if (String.IsNullOrEmpty(separator)) { Throw.ArgumentException(Argument.separator, Res.StringExtensionsSeparatorNullOrEmpty); } List <StringSegmentInternal> values = new StringSegmentInternal(s).Split(separator); int len = values.Count; byte[] result = new byte[len]; for (int i = 0; i < len; i++) { StringSegmentInternal segment = values[i]; segment.Trim(); if (!segment.TryParseIntQuick(false, Byte.MaxValue, out ulong value)) { Throw.ArgumentException(Argument.s, Res.StringExtensionsCannotParseAsType(segment.ToString(), Reflector.ByteType)); } result[i] = (byte)value; } return(result); }
/// <summary> /// Parses delimited hex values from a string into an array of bytes. /// </summary> /// <param name="s">A string containing delimited hex values.</param> /// <param name="separator">A separator delimiting the hex values. If <see langword="null"/>, then <paramref name="s"/> is parsed as a continuous hex stream.</param> /// <returns>A byte array containing the hex values as bytes.</returns> /// <exception cref="ArgumentNullException"><paramref name="s"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentException"><paramref name="separator"/> is <see langword="null"/> or empty, and <paramref name="s"/> does not consist of event number of hex digits, /// or parsing failed.</exception> public static byte[] ParseHexBytes(this string s, string separator) { if (s == null) { Throw.ArgumentNullException(Argument.s); } if (string.IsNullOrEmpty(separator)) { return(ParseHexBytes(s)); } List <StringSegmentInternal> values = new StringSegmentInternal(s).Split(separator); int len = values.Count; byte[] result = new byte[len]; for (int i = 0; i < len; i++) { StringSegmentInternal segment = values[i]; segment.Trim(); if (!Parser.TryParseHexByte(segment, out result[i])) { Throw.ArgumentException(Argument.s, Res.StringExtensionsCannotParseAsType(segment.ToString(), Reflector.ByteType)); } } return(result); }
private static bool TryParseBoolean(string s, CultureInfo culture, out object value) { var segment = new StringSegmentInternal(s); segment.Trim(); if (segment.EqualsOrdinalIgnoreCase(Boolean.FalseString)) { value = false; return(true); } if (segment.EqualsOrdinalIgnoreCase(Boolean.TrueString)) { value = true; return(true); } // allowing also an integer, which will be true for nonzero value if (segment.TryParseIntQuick(true, Int64.MaxValue, out ulong result)) { value = result != 0L; return(true); } value = null; return(false); }
internal static bool TryParseHexByte(StringSegmentInternal s, out byte value) { if (s.Length > 0) { s.TrimStart('0'); if (s.Length == 2 && TryParseHexDigit(s[0], out int hi) && TryParseHexDigit(s[1], out int lo)) { value = (byte)((hi << 4) | lo); return(true); } if (s.Length == 1 && TryParseHexDigit(s[0], out int result)) { value = (byte)result; return(true); } // if now empty it means valid 0 if (s.Length == 0) { value = 0; return(true); } } value = default; return(false); }
public static unsafe string GetRelativePath(string target, string baseDirectory, bool isCaseSensitive) { if (target == null) { Throw.ArgumentNullException(Argument.target); } if (target.Length == 0) { Throw.ArgumentException(Argument.target, Res.ArgumentEmpty); } if (baseDirectory == null) { Throw.ArgumentNullException(Argument.baseDirectory); } if (baseDirectory.Length == 0) { Throw.ArgumentException(Argument.baseDirectory, Res.ArgumentEmpty); } target = Path.GetFullPath(target); baseDirectory = Path.GetFullPath(baseDirectory); var srcDir = new StringSegmentInternal(baseDirectory); srcDir.TrimEnd(Path.DirectorySeparatorChar); List <StringSegmentInternal> basePathParts = srcDir.Split(Path.DirectorySeparatorChar); var dstDir = new StringSegmentInternal(target); dstDir.TrimEnd(Path.DirectorySeparatorChar); List <StringSegmentInternal> targetPathParts = dstDir.Split(Path.DirectorySeparatorChar); int commonPathDepth = 0; int len = Math.Min(basePathParts.Count, targetPathParts.Count); if (isCaseSensitive) { for (int i = 0; i < len; i++) { if (!basePathParts[i].Equals(targetPathParts[i])) { break; } commonPathDepth += 1; } } else { for (int i = 0; i < len; i++) { if (!basePathParts[i].EqualsOrdinalIgnoreCase(targetPathParts[i])) { break; } commonPathDepth += 1; } } // no common parts if (commonPathDepth == 0) { return(target); } int baseOnlyCount = basePathParts.Count - commonPathDepth; int targetPathCount = targetPathParts.Count; len = baseOnlyCount > 0 ? baseOnlyCount * 2 + (baseOnlyCount - 1) : 0; // .. and path separators for (int i = commonPathDepth; i < targetPathCount; i++) { if (len > 0) { len += 1; } len += targetPathParts[i].Length; } string result = new String('\0', len); fixed(char *pResult = result) { var sb = new MutableStringBuilder(pResult, len); for (int i = 0; i < baseOnlyCount; i++) { if (i > 0) { sb.Append(Path.DirectorySeparatorChar); } sb.Append(".."); } for (int i = commonPathDepth; i < targetPathCount; i++) { if (sb.Length > 0) { sb.Append(Path.DirectorySeparatorChar); } sb.Append(targetPathParts[i]); } } if (result.Length == 0) { return("."); } return(result); }
/// <summary> /// Tries to convert the string representation of the name or numeric value of one or more enumerated values to an equivalent enumerated object. /// In case of success the return value is <see langword="true"/> and parsed <see langword="enum"/> is returned in <paramref name="result"/> parameter. /// </summary> /// <param name="value">The <see cref="string">string</see> representation of the enumerated value or values to parse.</param> /// <param name="separator">In case of more values specifies the separator among the values. If <see langword="null"/> or is empty, then comma (<c>,</c>) separator is used.</param> /// <param name="ignoreCase">If <see langword="true"/>, ignores case; otherwise, regards case.</param> /// <param name="result">Returns the default value of <typeparamref name="TEnum"/>, if return value is <see langword="false"/>; otherwise, the parsed <see langword="enum"/> value.</param> /// <returns><see langword="false"/> if the <see cref="string">string</see> in <paramref name="value"/> parameter cannot be parsed as <typeparamref name="TEnum"/>; otherwise, <see langword="true"/>.</returns> /// <exception cref="ArgumentNullException"><paramref name="value"/> is <see langword="null"/>.</exception> public static bool TryParse(string value, string separator, bool ignoreCase, out TEnum result) { if (value == null) { Throw.ArgumentNullException(Argument.value); } // simple name match test (always case-sensitive) if (NameValuePairs.TryGetValue(value, out result)) { return(true); } var s = new StringSegmentInternal(value); s.Trim(); result = default(TEnum); if (s.Length == 0) { return(false); } // simple numeric value char c = s[0]; if (((c >= '0' && c <= '9') || c == '-' || c == '+') && s.TryParseIntQuick(underlyingInfo.IsSigned, underlyingInfo.MaxValue, out ulong numericValue)) { result = converter.ToEnum(numericValue); return(true); } // rest: flags enum or ignored case if (String.IsNullOrEmpty(separator)) { separator = EnumExtensions.DefaultParseSeparator; } ulong acc = 0UL; StringKeyedDictionary <ulong> dict = ignoreCase ? NameRawValuePairsIgnoreCase : NameRawValuePairs; while (s.TryGetNextSegment(separator, out StringSegmentInternal token)) { token.Trim(); if (token.Length == 0) { return(false); } // literal token found in dictionary if (dict.TryGetValue(token, out ulong tokens)) { acc |= tokens; continue; } // checking if is numeric token c = token[0]; if (((c >= '0' && c <= '9') || c == '-' || c == '+') && token.TryParseIntQuick(underlyingInfo.IsSigned, underlyingInfo.MaxValue, out numericValue)) { acc |= numericValue; continue; } // none of above return(false); } result = converter.ToEnum(acc); return(true); }
internal override int GetHashCode(StringSegmentInternal obj) => obj.GetHashCode();
internal override bool Equals(StringSegmentInternal x, string y) => x.Equals(y);
internal override bool Equals(StringSegmentInternal x, string y) => Throw.InternalError <bool>("Not expected to be called");
internal override int GetHashCode(StringSegmentInternal obj) => Throw.InternalError <int>("Not expected to be called");
internal override int GetHashCode(StringSegmentInternal obj) => obj.GetHashCodeOrdinalIgnoreCase();
internal override bool Equals(StringSegmentInternal x, string y) => x.EqualsOrdinalIgnoreCase(y);
private static bool TryParseKnownValueType <T>(string s, CultureInfo culture, out T value) { Debug.Assert(typeof(T).IsValueType, "T must be a value type so the branches can be optimized away by the JIT compiler"); // Important: // - Branches will be optimized away by JIT but only if we use typeof(SomeValueType) and not Reflector.XXXType // - In release build there will be no boxing for (T)(object)value and the JITted code will be much // simpler compared to the usually more elegant pattern matching if (typeof(T) == typeof(bool)) { var segment = new StringSegmentInternal(s); segment.Trim(); if (segment.EqualsOrdinalIgnoreCase(Boolean.FalseString)) { value = (T)(object)false; return(true); } if (segment.EqualsOrdinalIgnoreCase(Boolean.TrueString)) { value = (T)(object)true; return(true); } // allowing also an integer, which will be true for nonzero value if (segment.TryParseIntQuick(true, Int64.MaxValue, out ulong result)) { value = (T)(object)(result != 0L); return(true); } value = default; return(false); } if (typeof(T) == typeof(byte)) { if (Byte.TryParse(s, NumberStyles.Integer, culture, out byte result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(sbyte)) { if (SByte.TryParse(s, NumberStyles.Integer, culture, out sbyte result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(short)) { if (Int16.TryParse(s, NumberStyles.Integer, culture, out short result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(ushort)) { if (UInt16.TryParse(s, NumberStyles.Integer, culture, out ushort result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(int)) { if (Int32.TryParse(s, NumberStyles.Integer, culture, out int result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(uint)) { if (UInt32.TryParse(s, NumberStyles.Integer, culture, out uint result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(long)) { if (Int64.TryParse(s, NumberStyles.Integer, culture, out long result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(ulong)) { if (UInt64.TryParse(s, NumberStyles.Integer, culture, out ulong result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(IntPtr)) { if (Int64.TryParse(s, NumberStyles.Integer, culture, out long result)) { value = (T)(object)new IntPtr(result); return(true); } } if (typeof(T) == typeof(UIntPtr)) { if (UInt64.TryParse(s, NumberStyles.Integer, culture, out ulong result)) { value = (T)(object)new UIntPtr(result); return(true); } } if (typeof(T) == typeof(char)) { if (Char.TryParse(s, out char result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(float)) { if (Single.TryParse(s, floatStyle, culture, out float result)) { if (result.Equals(0f) && s.Trim().StartsWith(culture.NumberFormat.NegativeSign, StringComparison.Ordinal)) { result = FloatExtensions.NegativeZero; } value = (T)(object)result; return(true); } } if (typeof(T) == typeof(double)) { if (Double.TryParse(s, floatStyle, culture, out double result)) { if (result.Equals(0d) && s.Trim().StartsWith(culture.NumberFormat.NegativeSign, StringComparison.Ordinal)) { result = DoubleExtensions.NegativeZero; } value = (T)(object)result; return(true); } } if (typeof(T) == typeof(decimal)) { if (Decimal.TryParse(s, floatStyle, culture, out decimal result)) { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(TimeSpan)) { #if NET35 if (TimeSpan.TryParse(s, out TimeSpan result)) #else if (TimeSpan.TryParse(s, culture, out TimeSpan result)) #endif { value = (T)(object)result; return(true); } } if (typeof(T) == typeof(DateTime)) { s = s.TrimEnd(); if (s.Length > 0) { DateTimeStyles style = s[s.Length - 1] == 'Z' ? DateTimeStyles.AdjustToUniversal : DateTimeStyles.None; if (DateTime.TryParse(s, culture, style, out DateTime result)) { value = (T)(object)result; return(true); } } } if (typeof(T) == typeof(DateTimeOffset)) { s = s.TrimEnd(); if (s.Length > 0) { DateTimeStyles style = s[s.Length - 1] == 'Z' ? DateTimeStyles.AdjustToUniversal : DateTimeStyles.None; if (DateTimeOffset.TryParse(s, culture, style, out DateTimeOffset result)) { value = (T)(object)result; return(true); } } } value = default; return(false); }