using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Web; using miew.Enumerable; namespace miew.String { using Array = System.Array; using String = System.String; [DebuggerDisplay("{ToString(),nq}")] public sealed class ImmutableStringArray : IList<String>, IEquatable<ImmutableStringArray> { readonly String[] arr; readonly int hc = 0; readonly IEqualityComparer<String> comparer; public ImmutableStringArray(IEnumerable<String> rgs, IEqualityComparer<String> comparer) { this.arr = rgs as String[] ?? rgs.ToArray(); this.comparer = comparer ?? StringComparer.Ordinal; hc = arr.Length; for (int i = 0; i < arr.Length; i++) hc = hc ^ (i + arr[i].GetHashCode()); } public String this[int index] { get { return arr[index]; } set { throw new InvalidOperationException(); } } public int IndexOf(String item) { return Array.IndexOf<String>(arr, item); } public bool Contains(String item) { return Array.IndexOf<String>(arr, item) != -1; } public void CopyTo(String[] array, int arrayIndex) { Array.Copy(arr, array, arr.Length); } public int Count { get { return arr.Length; } } public bool IsReadOnly { get { return true; } } public IEnumerator<String> GetEnumerator() { return arr.AsEnumerable<String>().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return arr.GetEnumerator(); } public void Insert(int index, string item) { throw new InvalidOperationException(); } public void RemoveAt(int index) { throw new InvalidOperationException(); } public void Add(String item) { throw new InvalidOperationException(); } public void Clear() { throw new InvalidOperationException(); } public bool Remove(String item) { throw new InvalidOperationException(); } public bool Equals(ImmutableStringArray other) { return hc == other.hc && arr.SequenceEqual(other.arr, comparer); } public override bool Equals(Object obj) { ImmutableStringArray o = obj as ImmutableStringArray; return o != null && hc == o.hc && arr.SequenceEqual(o.arr, comparer); } public override int GetHashCode() { return hc; } public override String ToString() { return String.Join(" ", arr.Select(s => "[" + s + "]")); } }; public static class Extensions { public static String NewString(this IEnumerable<Char> iech) { return new String(iech as Char[] ?? iech.ToArray()); } public static String Quotes(this String s) { return "\"" + s + "\""; } public static String RightEllipses(this String s, int c) { if (s.Length < c) return s; return s.Remove(c - 3) + "..."; } public static String LeftEllipses(this String s, int c) { if (s.Length < c) return s; return "..." + s.Substring(3); } static String[] nl_sep = { Environment.NewLine }; public static String Indent(this String s, int c) { String ind = new String(' ', c); if (!s.Contains(Environment.NewLine)) return ind + s; return s.Split(nl_sep, StringSplitOptions.RemoveEmptyEntries).Select(x => ind + x).StringJoin(Environment.NewLine); } #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String StringJoin(this IEnumerable<String> ie) { return String.Join(String.Empty, ie.ToArray()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String StringJoin(this IEnumerable<String> ie, String sep) { return String.Join(sep, ie.ToArray()); } public static Dictionary<String, int> Tally(this IEnumerable<String> ies) { Dictionary<String, int> d = new Dictionary<String, int>(); foreach (String s in ies) if (d.ContainsKey(s)) d[s]++; else d.Add(s, 1); return d; } #endif public static String Intern(this String s) { return String.Intern(s); } public static IEnumerable<String> Lines(this String s) { return miew.IO.Extensions.Lines(new StringReader(s)); } public static String RemoveMatchedParentheses(this String s, out bool f_all_matched) { f_all_matched = true; int nest = 0, i_start = 0; Char prev = default(Char); for (int i = 0; i < s.Length; i++) { Char ch = s[i]; if (ch == '(' && prev != '\\') { if (nest == 0) i_start = i; nest++; } if (ch == ')' && prev != '\\') { nest--; if (nest < 0) break; if (nest == 0) { s = s.Remove(i, 1).Remove(i_start, 1); i = i_start; } } prev = ch; } f_all_matched = nest == 0; return s; } public static String ExtractParenthesized(this String s) { int j, k; if ((j = s.IndexOf('(')) >= 0) if ((k = s.IndexOf(')', j)) > 0) s = s.Substring(j + 1, k - j - 1); return s; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String RemoveParenthesized(this String s) { int j, k = 0; while ((j = s.IndexOf('(', k)) >= 0) { if ((k = s.IndexOf(')', j)) == -1) break; s = s.Remove(j, k + 1 - j); k = j; } return s; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String RemoveBracketed(this String s) { int j, k = 0; while ((j = s.IndexOf('[', k)) >= 0) { if ((k = s.IndexOf(']', j)) == -1) break; s = s.Remove(j, k + 1 - j); k = j; } return s; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String RemoveAngleTagged(this String s) { int j, k = 0; while ((j = s.IndexOf('<', k)) >= 0) { if ((k = s.IndexOf('>', j)) == -1) break; s = s.Remove(j, k + 1 - j); k = j; } return s; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String ExtractAngleTagged(this String s) { int j, k; return (j = s.IndexOf('<')) >= 0 && (k = s.IndexOf('>', j)) > 0 ? s.Substring(j + 1, k - j - 1) : String.Empty; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static unsafe int CopyToNativeW(this String s, Char* pbuf, int cwch_max) { int c = s.Length; if (c + 1 > cwch_max) return 0; fixed (Char* p = s) pbuf[Encoding.Unicode.GetBytes(p, c, (byte*)pbuf, cwch_max * sizeof(Char)) >> 1] = '\0'; return c + 1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// ''' was introduced as a standard entity in XML, and thus is also standard in XHTML. For maximum compatibility, /// author ' instead. /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String XhtmlEncode(this String s) { return HttpUtility.HtmlEncode(s).Replace("\'", "'"); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// ''' was introduced as a standard entity in XML, and thus is also standard in XHTML. For maximum /// compatibility, author ' instead. /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String XhtmlDecode(this String s) { return HttpUtility.HtmlDecode(s).Replace("'", "'"); } /// <summary> /// Probably not for use with LISP /// </summary> public static int QuoteInsulatedIndexOf(this String s, Char ch_find) { Stack<Char> stk = new Stack<Char>(); for (int i = 0; i < s.Length; i++) { Char ch = s[i]; if ((ch == '\'' || ch == '\"') && (i < 1 || s[i - 1] != '\\' || i < 2 || s[i - 2] != '\\')) { if (stk.Count > 0 && ch == stk.Peek()) stk.Pop(); else stk.Push(ch); } else if (stk.Count == 0 && ch == ch_find) return i; } return -1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static IEnumerable<String> QuoteInsulatedSplit(this String s, Char ch_sep) { int cb, i, i_last = 0; Stack<Char> stk = new Stack<Char>(); for (i = 0; i < s.Length; i++) { Char ch = s[i]; if (ch == '\'' || ch == '\"') { if (stk.Count > 0 && ch == stk.Peek()) stk.Pop(); else stk.Push(ch); } else if (stk.Count == 0 && ch == ch_sep) { if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); i_last = i + 1; } } if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); if (stk.Count != 0) throw new Exception(); } #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static IEnumerable<String> QuoteInsulatedSplit(this String s, params Char[] rgch) { int cb, i, i_last = 0; Stack<Char> stk = new Stack<Char>(); for (i = 0; i < s.Length; i++) { Char ch = s[i]; if (ch == '\'' || ch == '\"') { if (stk.Count > 0 && ch == stk.Peek()) stk.Pop(); else stk.Push(ch); } else if (stk.Count == 0 && Array.IndexOf<Char>(rgch, ch) != -1) { if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); i_last = i + 1; } } if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); #if (DEBUG) if (stk.Count != 0) throw new Exception(); #endif } #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static IEnumerable<String> InsulatedSplit(this String s, Char ins, params Char[] split_chars) { bool f_enable = true; int cb, i, i_last = 0; for (i = 0; i < s.Length; i++) { if (s[i] == ins) f_enable = !f_enable; else if (f_enable && Array.IndexOf<Char>(split_chars, s[i]) != -1) { if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); i_last = i + 1; } } if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static IEnumerable<String> InsulatedSplitWithEscape(this String s, Char ins, params Char[] split_chars) { bool f_enable = true; int cb, i, i_last = 0; for (i = 0; i < s.Length; i++) { if (s[i] == ins && (i == 0 || s[i - 1] != '\\')) f_enable = !f_enable; else if (f_enable && Array.IndexOf<Char>(split_chars, s[i]) != -1) { if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); i_last = i + 1; } } if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); } #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static IEnumerable<String> InsulatedSplit(this String s, Char[] ins, params Char[] split_chars) { Char wait_for = default(Char); int cb, i, i_last = 0; for (i = 0; i < s.Length; i++) { Char ch = s[i]; int v = Array.IndexOf<Char>(ins, ch); if (v != -1) { if (ch == wait_for) wait_for = default(Char); else wait_for = ch; } else if (wait_for == default(Char) && Array.IndexOf<Char>(split_chars, ch) != -1) { if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); i_last = i + 1; } } if ((cb = i - i_last) > 0) yield return s.Substring(i_last, cb); } #endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String Left(this String s, int cch) { if (s == null || s.Length == 0) return String.Empty; return (s.Length <= cch) ? s : s.Substring(0, cch); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String TrimEndOrPadRight(this String s, int cch) { if (s == null) return cch == 0 ? String.Empty : new String(' ', cch); int c = s.Length; if (c == cch) return s; if (c == 0) return new String(' ', cch); if (c < cch) return s.PadRight(cch); return s.Substring(0, cch); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String TrimEndOrPadLeft(this String s, int cch) { if (s == null) return cch == 0 ? String.Empty : new String(' ', cch); int c = s.Length; if (c == cch) return s; if (c == 0) return new String(' ', cch); if (c < cch) return s.PadLeft(cch); return s.Remove(cch); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String Right(this String s, int cch) { return (s.Length <= cch) ? s : s.Substring(s.Length - cch); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String PadCenter(this String s, int width, char pad_char) { if (s == null || width <= s.Length) return s; return s.PadLeft(s.Length + (width - s.Length) / 2, pad_char).PadRight(width, pad_char); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String SubstringOrLess(this String s, int idx, int cch) { if (String.IsNullOrEmpty(s)) return String.Empty; int c = s.Length; if (idx >= c) return String.Empty; if (idx + cch > c) cch = c - idx; return s.Substring(idx, cch); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// It's important to not spuriously create new strings /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool SubstringStartsWith(this String s, int i, String s_compare) { if (s_compare.Length > s.Length - i) return false; for (int j = 0; j < s_compare.Length; j++) if (s_compare[j] != s[i++]) return false; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// It's important to not spuriously create new strings /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool ToLowerSubstringStartsWith(this String s, int i, String s_compare) { if (s_compare.Length > s.Length - i) return false; for (int j = 0; j < s_compare.Length; j++) if (s_compare[j] != Char.ToLower(s[i++])) return false; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool HasNonSpaceChars(this String s) { foreach (Char ch in s) if (ch != ' ') return true; return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool IsAllWhitespace(this String s) { int c = s.Length; for (int i = 0; i < c; i++) if (!Char.IsWhiteSpace(s[i])) return false; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String RemoveSpaces(this String s) { return new String(s.Where(ch => ch != ' ').ToArray()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String WhitespaceToSpace(this String s) { return new String(s.Select(e => Char.IsWhiteSpace(e) ? ' ' : e).ToArray()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String CondenseSpaces(this String s_in) { if (s_in.Length < 2) return s_in; int j = 0; while ((j = s_in.IndexOf(' ', j)) != -1) { int k = ++j; while (k < s_in.Length && s_in[k] == ' ') k++; int c = k - j; if (c > 0) s_in = s_in.Remove(j, c); } return s_in; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String SmartQuotes(this String s) { int i = 0; return new String(s.Select(ch => ch == '\"' ? ((i++ & 0x01) == 0 ? '“' : '”') : ch).ToArray()); } public static String SmartQuotes(this String s, bool f_span) { int i = 0; Char[] rgch = s.ToCharArray(); StringBuilder sb = new StringBuilder(); foreach (Char ch in rgch) { if (ch == '\"') { if ((i++ & 0x01) == 0) sb.Append("<span style='font-family:cambria;'>“</span>"); else sb.Append("<span style='font-family:cambria;'>”</span>"); } else sb.Append(ch); } return sb.ToString(); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool IsAllDigits(this String s) { int i; for (i = 0; i < s.Length; i++) if (!miew.Character.Extensions.IsDigit(s[i])) return false; return (i > 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String RemoveZWSP(this String s) { return new String(s.Where(e => e != '\x200b').ToArray()); } } namespace Thai { using String = System.String; using miew.Character.Thai; public static class Extensions { static Char[] digits = "๐๑๒๓๔๕๖๗๘๙".ToCharArray(); public static String ToThaiDigits(this String s) { return new String(s.Select(ch => '0' <= ch && ch <= '9' ? digits[ch - '0'] : ch).ToArray()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool IsTIS620(this String s) { for (int i = 0; i < s.Length; i++) if (s[i] < 161) return false; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static readonly Encoding enc_874 = Encoding.GetEncoding(874); public static String ToThin874(this String s) { return Encoding.GetEncoding(1252).GetString(enc_874.GetBytes(s)); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static unsafe int EncodeToNative874(this String s, byte* pbuf, int cch_max) { int c = s.Length; if (c + 1 > cch_max) return 0; fixed (Char* p = s) pbuf[enc_874.GetBytes(p, c, (byte*)pbuf, cch_max)] = 0; return c + 1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static readonly HashSet<Char> ok_874_chars = new HashSet<Char>(enc_874.GetString(System.Linq.Enumerable.Range(0, 255).Select(e => (byte)e).ToArray())); static String EscapeNonTis620(this String s) { String[] rgs = s.Select(e => { if (ok_874_chars.Contains(e)) return e.ToString(); else return String.Format("&#{0};", (int)e); }).ToArray(); return String.Join(String.Empty, rgs); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static Char FirstThaiCons(this String s) { foreach (Char c in s.ToCharArray()) if (c.IsThaiCons()) return c; return default(Char); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String NormalizeYamok(this String s) { int j = 0; while ((j = s.IndexOf(" ๆ", j)) >= 0) s = s.Remove(j, 1); return s; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static bool ContainsThai(this String s) { return s.Any(ch => ch.IsThai()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String StripDotAndPhinthu(this String s_in) { return new String(s_in.Where(e => e != 'ฺ' && e != '•').ToArray()); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static readonly Char[] DotPhinthu = { '•', 'ฺ' }; public static bool ContainsDotOrPhinthu(this String s_in) { return s_in.IndexOfAny(DotPhinthu) != -1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static unsafe String RemoveDiacritics(this String s_in) { String norm = s_in.Normalize(NormalizationForm.FormD); fixed (Char* pin_s = norm) { Char* p_end = pin_s + norm.Length; Char* p = pin_s; while (p < p_end) { if (!(*p).IsThai() && CharUnicodeInfo.GetUnicodeCategory(*p) == UnicodeCategory.NonSpacingMark) goto yes_convert; p++; } return s_in; yes_convert: StringBuilder sb = new StringBuilder(norm.Substring(0, (int)(p - pin_s)), norm.Length); p++; // skip the one detected above while (p < p_end) { if ((*p).IsThai() || CharUnicodeInfo.GetUnicodeCategory(*p) != UnicodeCategory.NonSpacingMark) sb.Append(*p); p++; } return sb.ToString(); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static String Reinterpret(this String s_in, bool f_bullet) { return new String(s_in.Select(e => e.Reinterpret(f_bullet)).ToArray()); } }; }; namespace Builder { public static class Extensions { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static StringBuilder AppendFormatLine(this StringBuilder sb, String format, params Object[] args) { return sb.AppendLine(String.Format(format, args)); } }; #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static unsafe void Append(this StringBuilder sb, Char* p, int cch) { #if true // this tests much faster than what follows sb.Append(new String(p, 0, cch)); #else // seems to be no way to blt the internal contents if (cch == 0 || p == null) return; int idx = sb.Length; sb.Length += cch; Char* p_end = p + cch; while (p < p_end) sb[idx++] = *p++; #endif } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static int IndexOf(this StringBuilder sb, String s) { return IndexOf(sb, s, 0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static int IndexOf(this StringBuilder sb, String s, int startIndex) { if (s == null) s = String.Empty; for (int i = startIndex; i < sb.Length; i++) { int j; for (j = 0; j < s.Length && i + j < sb.Length && sb[i + j] == s[j]; j++) ; if (j == s.Length) return i; } return -1; } #endif } namespace Thin { using miew.Array; using String = System.String; public static class Extensions { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Convert byte array to its thin string /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static unsafe String ToThin(this Byte[] rgb) { fixed (Byte* pb = rgb) return Marshal.PtrToStringAnsi(new IntPtr(pb), rgb.Length); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Split the array of bytes into portions delimited by multibyte separator 'sep' /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static IEnumerable<Byte[]> Split(this Byte[] rgb, Byte[] sep) { int cb, i, i_prev = 0; for (i = 0; i < rgb.Length; ) { if (rgb.ValueCompare<Byte>(i, sep)) { if ((cb = i - i_prev) != 0) { Byte[] ret = new Byte[cb]; Buffer.BlockCopy(rgb, i_prev, ret, 0, cb); yield return ret; } i += sep.Length; i_prev = i; } else i++; } if ((cb = i - i_prev) > 0) { Byte[] ret = new Byte[cb]; Buffer.BlockCopy(rgb, i_prev, ret, 0, cb); yield return ret; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Split the array of bytes into portions delimited by thin string 'thin' /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static IEnumerable<Byte[]> Split(this Byte[] src, String thin) { foreach (Byte[] ret in src.Split(thin.ToByteArr())) yield return ret; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static int IndexOf(this Byte[] a, Byte[] b) { if (b.Length > a.Length) return -1; int term = a.Length - b.Length + 1; for (int i = 0; i < term; i++) { if (a.ValueCompare<Byte>(i, b)) return i; } return -1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Convert a thin string to its byte array /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static unsafe Byte[] ToByteArr(this String thin) { Byte[] rgb = new Byte[thin.Length]; fixed (Char* _p_src = thin) fixed (Byte* _p_dst = rgb) { Char* p = _p_src; Char* p_end = p + thin.Length; Byte* p_dst = _p_dst; while (p < p_end) *p_dst++ = (Byte)(*p++); } return rgb; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Append the thin string's bytes to the list of bytes /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public static void Append(this List<Byte> l, String thin) { l.AddRange(thin.ToByteArr()); } }; } }