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