You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1229 lines
						
					
					
						
							44 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							1229 lines
						
					
					
						
							44 KiB
						
					
					
				
								using Apewer.Internals;
							 | 
						|
								using System;
							 | 
						|
								using System.Collections;
							 | 
						|
								using System.Collections.Generic;
							 | 
						|
								using System.Runtime.InteropServices;
							 | 
						|
								using System.Text;
							 | 
						|
								using System.Text.RegularExpressions;
							 | 
						|
								
							 | 
						|
								namespace Apewer
							 | 
						|
								{
							 | 
						|
								
							 | 
						|
								    /// <summary>文本实用工具。</summary>
							 | 
						|
								    public static class TextUtility
							 | 
						|
								    {
							 | 
						|
								
							 | 
						|
								        const string BlankChars = "  \n\r\t\f\b\a"; // 在 IsBlank 和 Trim 中视为空白的字符。
							 | 
						|
								        const string LineFeed = "\r\n"; // 换行符,由 ASCII 13 和 ASCII 10 组成。
							 | 
						|
								        const string SpaceDbc = " ";
							 | 
						|
								        const string SpaceSbc = " ";
							 | 
						|
								        const string LucidChars = "3456789acefhknpstwxyz";
							 | 
						|
								        const string KeyChars = "0123456789abcdefghijklmnopqrstuvwxyz";
							 | 
						|
								        const string HexChars = "0123456789abcdef";
							 | 
						|
								        const string NumericChars = "0123456789";
							 | 
						|
								        const string LowerChars = "abcdefghijklmnopqrstuvwxyz";
							 | 
						|
								        const string UpperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
							 | 
						|
								        const string LetterChars = LowerChars + UpperChars;
							 | 
						|
								
							 | 
						|
								        /// <summary>UTF-8 BOM。</summary>
							 | 
						|
								        public static byte[] Bom { get => new byte[] { 0xEF, 0xBB, 0xBF }; }
							 | 
						|
								
							 | 
						|
								        /// <summary>CRLF。</summary>
							 | 
						|
								        public const string CRLF = "\r\n";
							 | 
						|
								
							 | 
						|
								        /// <summary>LF。</summary>
							 | 
						|
								        public const string LF = "\n";
							 | 
						|
								
							 | 
						|
								        /// <summary>长度为 0 的空字符串。</summary>
							 | 
						|
								        public const string Empty = "";
							 | 
						|
								
							 | 
						|
								        /// <summary>无效指针。</summary>
							 | 
						|
								        public const string Null = null;
							 | 
						|
								
							 | 
						|
								        /// <summary>返回表示指定对象的字符串。</summary>
							 | 
						|
								        public static string Text(object value)
							 | 
						|
								        {
							 | 
						|
								            if (value is string str) return str;
							 | 
						|
								            if (value == null) return null;
							 | 
						|
								            if (value.Equals(DBNull.Value)) return null;
							 | 
						|
								
							 | 
						|
								            if (value is Type t) return t.Name;
							 | 
						|
								            if (value is char[] chars) return new string(chars);
							 | 
						|
								
							 | 
						|
								            var type = value.GetType();
							 | 
						|
								            var toString = type.GetMethod(nameof(object.ToString), Type.EmptyTypes);
							 | 
						|
								            if (toString.DeclaringType.Equals(type))
							 | 
						|
								            {
							 | 
						|
								                try { return value.ToString(); }
							 | 
						|
								                catch { return null; }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return "<" + type.Name + ">";
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>字符串为空。</summary>
							 | 
						|
								        public static bool IsEmpty(string text) => text == null || text == Empty;
							 | 
						|
								
							 | 
						|
								        /// <summary>字符串不为空。</summary>
							 | 
						|
								        public static bool NotEmpty(string text) => text != null && text != Empty;
							 | 
						|
								
							 | 
						|
								        /// <summary>字符串为空,或只含有空白字符。</summary>
							 | 
						|
								        public static bool IsBlank(string text)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text)) return true;
							 | 
						|
								            var length = text.Length;
							 | 
						|
								            var bcs = BlankChars.ToCharArray();
							 | 
						|
								            var bcl = bcs.Length;
							 | 
						|
								            bool b;
							 | 
						|
								            char c;
							 | 
						|
								            for (var i = 0; i < length; i++)
							 | 
						|
								            {
							 | 
						|
								                c = text[i];
							 | 
						|
								                b = false;
							 | 
						|
								                for (var j = 0; j < bcl; j++)
							 | 
						|
								                {
							 | 
						|
								                    if (c == bcs[j])
							 | 
						|
								                    {
							 | 
						|
								                        b = true;
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								                if (!b) return false;
							 | 
						|
								            }
							 | 
						|
								            return true;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>字符串不为空,切含有非空白字符。</summary>
							 | 
						|
								        public static bool NotBlank(string text) => !IsBlank(text);
							 | 
						|
								
							 | 
						|
								        /// <summary>获取文本的 Int32 哈希。</summary>
							 | 
						|
								        private static int HashCode(string text)
							 | 
						|
								        {
							 | 
						|
								            if (text == null) return 0;
							 | 
						|
								            int hash = 0;
							 | 
						|
								            var length = text.Length;
							 | 
						|
								            for (int i = 0; i < length; i++)
							 | 
						|
								            {
							 | 
						|
								                hash = 31 * hash + text[i];
							 | 
						|
								            }
							 | 
						|
								            return hash;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        private static string PrivateJoin(string separator, IEnumerable cells)
							 | 
						|
								        {
							 | 
						|
								            if (cells == null) return Empty;
							 | 
						|
								            if (cells is string str) return str ?? "";
							 | 
						|
								
							 | 
						|
								            var sb = new StringBuilder();
							 | 
						|
								            var first = true;
							 | 
						|
								            var hasSeparator = !string.IsNullOrEmpty(separator);
							 | 
						|
								            foreach (var cell in cells)
							 | 
						|
								            {
							 | 
						|
								                if (cell == null) continue;
							 | 
						|
								                var text = null as string;
							 | 
						|
								
							 | 
						|
								                if (cell is string) text = cell as string;
							 | 
						|
								                else if (cell is Type type) text = type.Name;
							 | 
						|
								                else cell.ToString();
							 | 
						|
								
							 | 
						|
								                if (string.IsNullOrEmpty(text)) continue;
							 | 
						|
								                if (!first && hasSeparator) sb.Append(separator);
							 | 
						|
								                first = false;
							 | 
						|
								                sb.Append(text);
							 | 
						|
								            }
							 | 
						|
								            var result = sb.ToString();
							 | 
						|
								            return result;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>合并为字符串。</summary>
							 | 
						|
								        public static string Merge(params object[] cells) => Join(null, cells);
							 | 
						|
								
							 | 
						|
								        /// <summary>合并为字符串。</summary>
							 | 
						|
								        public static string Join(string separator, params object[] cells)
							 | 
						|
								        {
							 | 
						|
								            if (cells == null) return Empty;
							 | 
						|
								
							 | 
						|
								            while (cells.Length == 1)
							 | 
						|
								            {
							 | 
						|
								                var first = cells[0];
							 | 
						|
								                if (first.IsNull()) return Empty;
							 | 
						|
								                if (first is string str) return str ?? Empty;
							 | 
						|
								
							 | 
						|
								                if (first is IEnumerable<char> chars)
							 | 
						|
								                {
							 | 
						|
								                    var list = new List<char>();
							 | 
						|
								                    foreach (var @char in chars) list.Add(@char);
							 | 
						|
								                    return new string(list.ToArray());
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                if (!first.GetType().IsValueType && first is IEnumerable enumerable)
							 | 
						|
								                {
							 | 
						|
								                    var list = new List<object>();
							 | 
						|
								                    foreach (var item in enumerable) list.Add(item);
							 | 
						|
								                    cells = list.ToArray();
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								                break;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            {
							 | 
						|
								                var sb = new StringBuilder();
							 | 
						|
								                var first = true;
							 | 
						|
								                var hasSeparator = !string.IsNullOrEmpty(separator);
							 | 
						|
								                foreach (var cell in cells)
							 | 
						|
								                {
							 | 
						|
								                    if (cell.IsNull()) continue;
							 | 
						|
								
							 | 
						|
								                    var text = null as string;
							 | 
						|
								                    if (cell is string str) text = str;
							 | 
						|
								                    else if (cell is char[] chars) text = new string(chars);
							 | 
						|
								                    else text = Text(cell);
							 | 
						|
								
							 | 
						|
								                    if (string.IsNullOrEmpty(text)) continue;
							 | 
						|
								                    if (hasSeparator)
							 | 
						|
								                    {
							 | 
						|
								                        if (first) first = false;
							 | 
						|
								                        else sb.Append(separator);
							 | 
						|
								                    }
							 | 
						|
								                    sb.Append(text);
							 | 
						|
								                }
							 | 
						|
								                var result = sb.ToString();
							 | 
						|
								                return result;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>重复指定字符,直到达到指定长度。</summary>
							 | 
						|
								        /// <param name="cell">要重复的字符。</param>
							 | 
						|
								        /// <param name="count">重复的次数。</param>
							 | 
						|
								        public static string Duplicate(char cell, int count)
							 | 
						|
								        {
							 | 
						|
								            if (count < 1) return Empty;
							 | 
						|
								            var chars = new char[count];
							 | 
						|
								            for (var i = 0; i < count; i++) chars[i] = cell;
							 | 
						|
								            return new string(chars);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>重复指定字符串,直到达到指定长度。</summary>
							 | 
						|
								        /// <param name="cell">要重复的字符串。</param>
							 | 
						|
								        /// <param name="count">重复的次数。</param>
							 | 
						|
								        public static string Duplicate(string cell, int count)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(cell) || count < 1) return Empty;
							 | 
						|
								            var length = cell.Length;
							 | 
						|
								            var total = length * count;
							 | 
						|
								            var output = new char[total];
							 | 
						|
								            var input = cell.ToCharArray();
							 | 
						|
								            for (var i = 0; i < count; i++)
							 | 
						|
								            {
							 | 
						|
								                Array.Copy(input, 0, output, length * i, length);
							 | 
						|
								            }
							 | 
						|
								            return new string(output);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>获取指定长的的空格。</summary>
							 | 
						|
								        public static string Space(int length) => Duplicate(' ', length);
							 | 
						|
								
							 | 
						|
								        /// <summary>将文本以转换为字节数组。默认 Encoding 为 UTF-8。</summary>
							 | 
						|
								        public static byte[] Bytes(string text, Encoding encoding = null)
							 | 
						|
								        {
							 | 
						|
								            if (text == null || text == Empty) return BytesUtility.Empty;
							 | 
						|
								            try { return (encoding ?? Encoding.UTF8).GetBytes(text); }
							 | 
						|
								            catch { return BytesUtility.Empty; }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>将字节数组转换为文本。默认 Encoding 为 UTF-8。</summary>
							 | 
						|
								        public static string FromBytes(byte[] bytes, Encoding encoding = null)
							 | 
						|
								        {
							 | 
						|
								            if (bytes == null || bytes.LongLength < 1L) return Empty;
							 | 
						|
								
							 | 
						|
								            // 计算非零字节的长度
							 | 
						|
								            var count = 0;
							 | 
						|
								            for (var i = 0; i < bytes.Length; i++)
							 | 
						|
								            {
							 | 
						|
								                if (bytes[i] == 0) continue;
							 | 
						|
								                count++;
							 | 
						|
								            }
							 | 
						|
								            if (count < 1) return Empty;
							 | 
						|
								
							 | 
						|
								            // 转换
							 | 
						|
								            if (encoding == null) encoding = Encoding.UTF8;
							 | 
						|
								            try
							 | 
						|
								            {
							 | 
						|
								                var result = encoding.GetString(bytes, 0, count);
							 | 
						|
								                return result;
							 | 
						|
								            }
							 | 
						|
								            catch { return Empty; }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>将明文文本以 UTF-8 转换为 Base64 文本。</summary>
							 | 
						|
								        public static string ToBase64(string plain)
							 | 
						|
								        {
							 | 
						|
								            if (plain == null || plain == Empty) return Empty;
							 | 
						|
								            return BytesUtility.ToBase64(Bytes(plain));
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>将 Base64 文本以 UTF-8 转换为明文文本。</summary>
							 | 
						|
								        public static string FromBase64(string cipher)
							 | 
						|
								        {
							 | 
						|
								            if (cipher == null || cipher == Empty) return Empty;
							 | 
						|
								            return FromBytes(BytesUtility.FromBase64(cipher));
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>从字符串中删除子字符串。</summary>
							 | 
						|
								        /// <param name="text">要查询的字符串。</param>
							 | 
						|
								        /// <param name="sub">子字符串。</param>
							 | 
						|
								        /// <param name="ignoreCase">是否忽略大小写。</param>
							 | 
						|
								        /// <returns>删除子字符串后的父字符串。</returns>
							 | 
						|
								        private static string Exlude(string text, string sub, bool ignoreCase = false)
							 | 
						|
								        {
							 | 
						|
								            if (string.IsNullOrEmpty(text)) return "";
							 | 
						|
								            if (string.IsNullOrEmpty(sub)) return text;
							 | 
						|
								            try
							 | 
						|
								            {
							 | 
						|
								                string vp = text;
							 | 
						|
								                string vs = sub;
							 | 
						|
								                string vr = "";
							 | 
						|
								                int vl;
							 | 
						|
								                int vi;
							 | 
						|
								                if (ignoreCase)
							 | 
						|
								                {
							 | 
						|
								                    vp = TextHelper.LCase(vp);
							 | 
						|
								                    vs = TextHelper.LCase(vs);
							 | 
						|
								                }
							 | 
						|
								                vl = vs.Length;
							 | 
						|
								                vi = 1;
							 | 
						|
								                while (vi <= (vp.Length - vl + 1))
							 | 
						|
								                {
							 | 
						|
								                    if (TextHelper.Middle(vp, vi, vl) == vs)
							 | 
						|
								                    {
							 | 
						|
								                        vi = vi + vl;
							 | 
						|
								                    }
							 | 
						|
								                    else
							 | 
						|
								                    {
							 | 
						|
								                        vr = vr + TextHelper.Middle(text, vi, 1);
							 | 
						|
								                        vi = vi + 1;
							 | 
						|
								                    }
							 | 
						|
								
							 | 
						|
								                }
							 | 
						|
								                return vr;
							 | 
						|
								            }
							 | 
						|
								            catch { return text; }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>替换字符串中的子字符串。</summary>
							 | 
						|
								        /// <param name="text">要查询的字符串。</param>
							 | 
						|
								        /// <param name="new">新子字符串,保留大小写。</param>
							 | 
						|
								        /// <param name="old">原子字符串。</param>
							 | 
						|
								        /// <param name="ignoreCase">查找时是否忽略父字符串和原子字符串大小写。</param>
							 | 
						|
								        /// <returns>替换后的父字符串。</returns>
							 | 
						|
								        private static string Replace(string text, string old, string @new, bool ignoreCase = false)
							 | 
						|
								        {
							 | 
						|
								            if (string.IsNullOrEmpty(text)) return "";
							 | 
						|
								            if (string.IsNullOrEmpty(old)) return text;
							 | 
						|
								            if (string.IsNullOrEmpty(@new)) return Exlude(text, old, ignoreCase);
							 | 
						|
								            if (TextHelper.Len(text) < TextHelper.Len(old)) return text;
							 | 
						|
								            if (ignoreCase)
							 | 
						|
								            {
							 | 
						|
								                try
							 | 
						|
								                {
							 | 
						|
								                    string p = TextHelper.LCase(text);
							 | 
						|
								                    string o = TextHelper.LCase(old);
							 | 
						|
								                    int vil = TextHelper.Len(old);
							 | 
						|
								                    int viv = 1;
							 | 
						|
								                    int vend = TextHelper.Len(text) - vil + 1;
							 | 
						|
								                    string vcell;
							 | 
						|
								                    string vresult = "";
							 | 
						|
								                    while (viv <= vend)
							 | 
						|
								                    {
							 | 
						|
								                        vcell = TextHelper.Middle(p, viv, vil);
							 | 
						|
								                        if (vcell == o)
							 | 
						|
								                        {
							 | 
						|
								                            vresult = vresult + @new;
							 | 
						|
								                            viv = viv + vil;
							 | 
						|
								                        }
							 | 
						|
								                        else
							 | 
						|
								                        {
							 | 
						|
								                            vresult = vresult + TextHelper.Middle(text, viv, 1);
							 | 
						|
								                            viv = viv + 1;
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                    return vresult;
							 | 
						|
								                }
							 | 
						|
								                catch { return text; }
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                try
							 | 
						|
								                {
							 | 
						|
								                    string vresult = text.Replace(old, @new);
							 | 
						|
								                    return vresult;
							 | 
						|
								                }
							 | 
						|
								                catch { return ""; }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>修复文本前缀。</summary>
							 | 
						|
								        /// <param name="text">原文本。</param>
							 | 
						|
								        /// <param name="include">TRUE:追加指定缀;FALSE:去除指定缀。</param>
							 | 
						|
								        /// <param name="head">前缀文本。</param>
							 | 
						|
								        public static string AssureStarts(string text, string head, bool include = true)
							 | 
						|
								        {
							 | 
						|
								            if (string.IsNullOrEmpty(text)) return Empty;
							 | 
						|
								            if (string.IsNullOrEmpty(head)) return text;
							 | 
						|
								
							 | 
						|
								            if (include)
							 | 
						|
								            {
							 | 
						|
								                return text.StartsWith(head) ? text : (head + text);
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                var headLength = head.Length;
							 | 
						|
								                if (!text.StartsWith(head)) return text;
							 | 
						|
								                var result = text;
							 | 
						|
								                while (true)
							 | 
						|
								                {
							 | 
						|
								                    result = result.Substring(headLength);
							 | 
						|
								                    if (!result.StartsWith(head)) return result;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>修复文本后缀。</summary>
							 | 
						|
								        /// <param name="text">原文本。</param>
							 | 
						|
								        /// <param name="include">TRUE:追加指定后缀;FALSE:去除指定后缀。</param>
							 | 
						|
								        /// <param name="foot">后缀文本。</param>
							 | 
						|
								        public static string AssureEnds(string text, string foot, bool include = true)
							 | 
						|
								        {
							 | 
						|
								            if (string.IsNullOrEmpty(text)) return Empty;
							 | 
						|
								            if (string.IsNullOrEmpty(foot)) return text;
							 | 
						|
								
							 | 
						|
								            if (include == true)
							 | 
						|
								            {
							 | 
						|
								                return text.EndsWith(foot) ? text : (text + foot);
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                var footLength = foot.Length;
							 | 
						|
								                if (!text.EndsWith(foot)) return text;
							 | 
						|
								                var result = text;
							 | 
						|
								                while (true)
							 | 
						|
								                {
							 | 
						|
								                    result = result.Substring(0, result.Length - footLength);
							 | 
						|
								                    if (!result.EndsWith(foot)) return result;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>用单字符作为分隔符拆分文本。</summary>
							 | 
						|
								        public static string[] Split(string text, char separator)
							 | 
						|
								        {
							 | 
						|
								            if (text == null) return new string[0];
							 | 
						|
								            if (text.Length < 1) return new string[] { "" };
							 | 
						|
								            if ((object)separator == null) return new string[] { text };
							 | 
						|
								
							 | 
						|
								            return text.Split(separator);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>用字符串作为分隔符拆分文本。</summary>
							 | 
						|
								        public static string[] Split(string text, string separator)
							 | 
						|
								        {
							 | 
						|
								            if (text == null) return new string[0];
							 | 
						|
								            if (text.Length < 1) return new string[] { "" };
							 | 
						|
								            if (string.IsNullOrEmpty(separator)) return new string[] { text };
							 | 
						|
								            if (separator.Length > text.Length) return new string[] { text };
							 | 
						|
								
							 | 
						|
								            var list = new List<string>();
							 | 
						|
								            var position = 0;
							 | 
						|
								            var total = text.Length;
							 | 
						|
								            var length = separator.Length;
							 | 
						|
								            var cell = new StringBuilder();
							 | 
						|
								            while (position < total)
							 | 
						|
								            {
							 | 
						|
								                var read = null as string;
							 | 
						|
								                if (position + length < total) read = text.Substring(position, length);
							 | 
						|
								                else read = text.Substring(position);
							 | 
						|
								
							 | 
						|
								                if (read == separator)
							 | 
						|
								                {
							 | 
						|
								                    if (cell.Length > 0)
							 | 
						|
								                    {
							 | 
						|
								                        list.Add(cell.ToString());
							 | 
						|
								                        // cell.Clear();
							 | 
						|
								                        cell = new StringBuilder();
							 | 
						|
								                    }
							 | 
						|
								                    else
							 | 
						|
								                    {
							 | 
						|
								                        list.Add("");
							 | 
						|
								                    }
							 | 
						|
								                    position += length;
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    cell.Append((char)text[position]);
							 | 
						|
								                    position += 1;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                if (position >= total)
							 | 
						|
								                {
							 | 
						|
								                    list.Add(cell.ToString());
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            var array = list.ToArray();
							 | 
						|
								            return array;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>用多个分隔符拆分文本。</summary>
							 | 
						|
								        public static string[] Split(string text, params char[] separators)
							 | 
						|
								        {
							 | 
						|
								            if (text == null) return new string[0];
							 | 
						|
								            if (text.Length < 1) return new string[] { "" };
							 | 
						|
								            if (separators == null || separators.Length < 1) return new string[] { text };
							 | 
						|
								            if (separators.Length == 1) return Split(text, separators[0]);
							 | 
						|
								
							 | 
						|
								            var list = new List<string>();
							 | 
						|
								            var separatorsText = new string(separators);
							 | 
						|
								            var sb = new StringBuilder();
							 | 
						|
								            foreach (var c in text)
							 | 
						|
								            {
							 | 
						|
								                if (separatorsText.IndexOf(c) >= 0)
							 | 
						|
								                {
							 | 
						|
								                    list.Add(sb.ToString());
							 | 
						|
								                    //sb.Clear();
							 | 
						|
								                    sb = new StringBuilder();
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								                sb.Append(c);
							 | 
						|
								            }
							 | 
						|
								            list.Add(sb.ToString());
							 | 
						|
								#if !NET20
							 | 
						|
								            sb.Clear();
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								            return list.ToArray();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>移除字符串前后的空字符。</summary>
							 | 
						|
								        /// <param name="text">原始字符串。</param>
							 | 
						|
								        /// <param name="trimBlank">移除空格、全角空格、换行符、回车符、制表符和换页符。</param>
							 | 
						|
								        public static string Trim(string text, bool trimBlank = false)
							 | 
						|
								        {
							 | 
						|
								            if (text == null || text == Empty) return Empty;
							 | 
						|
								            if (!trimBlank) return Trim(text, ' ');
							 | 
						|
								            return Trim(text, BlankChars.ToCharArray());
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>移除字符串前后的指定字符。</summary>
							 | 
						|
								        /// <param name="text">原始字符串。</param>
							 | 
						|
								        /// <param name="chars">要移除的字符。</param>
							 | 
						|
								        public static string Trim(string text, params char[] chars)
							 | 
						|
								        {
							 | 
						|
								            if (text == null || text == Empty) return Empty;
							 | 
						|
								            if (chars == null || chars.Length < 1) return text;
							 | 
						|
								
							 | 
						|
								            var length = text.Length;
							 | 
						|
								            var charsLength = chars.Length;
							 | 
						|
								
							 | 
						|
								            var starts = 0;
							 | 
						|
								            var offset = 0;
							 | 
						|
								            while (true)
							 | 
						|
								            {
							 | 
						|
								                if (offset >= length) break;
							 | 
						|
								                var c = text[offset];
							 | 
						|
								                var trim = false;
							 | 
						|
								                for (var i = 0; i < charsLength; i++)
							 | 
						|
								                {
							 | 
						|
								                    if (c == chars[i])
							 | 
						|
								                    {
							 | 
						|
								                        starts += 1;
							 | 
						|
								                        offset += 1;
							 | 
						|
								                        trim = true;
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								                if (trim) continue; else break;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            var ends = 0;
							 | 
						|
								            if (starts < length)
							 | 
						|
								            {
							 | 
						|
								                offset = length - 1;
							 | 
						|
								                while (true)
							 | 
						|
								                {
							 | 
						|
								                    if (offset <= starts) break;
							 | 
						|
								                    var c = text[offset];
							 | 
						|
								                    var trim = false;
							 | 
						|
								                    for (var i = 0; i < charsLength; i++)
							 | 
						|
								                    {
							 | 
						|
								                        if (c == chars[i])
							 | 
						|
								                        {
							 | 
						|
								                            ends += 1;
							 | 
						|
								                            offset -= 1;
							 | 
						|
								                            trim = true;
							 | 
						|
								                            break;
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                    if (trim) continue; else break;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            if (starts == 0 && ends == 0) return text;
							 | 
						|
								            return text.Substring(starts, length - starts - ends);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>修剪字符串数组,修剪元素,并去除空字符串。</summary>
							 | 
						|
								        public static string[] Trim(this IEnumerable<string> strings)
							 | 
						|
								        {
							 | 
						|
								            var ab = new ArrayBuilder<string>();
							 | 
						|
								            if (strings == null) return ab.Export();
							 | 
						|
								            foreach (var str in strings)
							 | 
						|
								            {
							 | 
						|
								                var trim = Trim(str);
							 | 
						|
								                if (string.IsNullOrEmpty(trim)) continue;
							 | 
						|
								                ab.Add(trim);
							 | 
						|
								            }
							 | 
						|
								            var array = ab.Export();
							 | 
						|
								            return array;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>剪取文本内容,若指定头部为空则从原文本首部起,若指定尾部为空则至原文本末尾。</summary>
							 | 
						|
								        /// <returns>剪取后的内容,不包含 head 和 foot。</returns>
							 | 
						|
								        public static string Cut(string text, string head = null, string foot = null)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text)) return Empty;
							 | 
						|
								
							 | 
						|
								            int start, length;
							 | 
						|
								            if (IsEmpty(head))
							 | 
						|
								            {
							 | 
						|
								                // none
							 | 
						|
								                if (IsEmpty(foot)) return Empty;
							 | 
						|
								
							 | 
						|
								                // foot
							 | 
						|
								                length = text.IndexOf(foot);
							 | 
						|
								                if (length < 1) return text;
							 | 
						|
								                return text.Substring(0, length);
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                if (IsEmpty(foot))
							 | 
						|
								                {
							 | 
						|
								                    // head
							 | 
						|
								                    start = text.IndexOf(head);
							 | 
						|
								                    if (start < 0) return text;
							 | 
						|
								                    start += head.Length;
							 | 
						|
								                    return text.Substring(start);
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // both
							 | 
						|
								                start = text.IndexOf(head);
							 | 
						|
								                if (start < 0) start = 0;
							 | 
						|
								                else start += head.Length;
							 | 
						|
								                var temp = start == 0 ? text : text.Substring(start);
							 | 
						|
								                length = temp.IndexOf(foot);
							 | 
						|
								                if (length < 0) return temp;
							 | 
						|
								                if (length == 0) return Empty;
							 | 
						|
								                return temp.Substring(0, length);
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>比较两个字符串的相似度。返回值大于 0,小于等于 1。</summary>
							 | 
						|
								        /// <param name="arg1"></param>
							 | 
						|
								        /// <param name="arg2"></param>
							 | 
						|
								        /// <returns></returns>
							 | 
						|
								        public static double Similarity(string arg1, string arg2) => Levenshtein.Compute(arg1, arg2).Rate;
							 | 
						|
								
							 | 
						|
								        /// <summary>生成新的 GUID。</summary>
							 | 
						|
								        public static string Guid(bool hyphenation = true, bool lower = true)
							 | 
						|
								        {
							 | 
						|
								            var guid = System.Guid.NewGuid();
							 | 
						|
								            var str = hyphenation ? guid.ToString() : guid.ToString("n");
							 | 
						|
								            if (!lower) str = str.ToUpper();
							 | 
						|
								            return str;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>生成新主键。</summary>
							 | 
						|
								        public static string Key() => System.Guid.NewGuid().ToString("n");
							 | 
						|
								
							 | 
						|
								        /// <summary>生成随机字符串,出现的字符由字符池指定,默认池包含数字和字母。</summary>
							 | 
						|
								        /// <param name="length">随机字符串的长度。</param>
							 | 
						|
								        /// <param name="pool">字符池,字符池中每个字符在随机字符串中出现的概率约等。</param>
							 | 
						|
								        public static string Random(int length, string pool = "0123456789abcdefghijklmnopqrstuvwxyz")
							 | 
						|
								        {
							 | 
						|
								            if (length < 1) return Empty;
							 | 
						|
								            if (IsEmpty(pool)) return Duplicate(SpaceDbc, length);
							 | 
						|
								            var array = new char[length];
							 | 
						|
								            var max = pool.Length - 1;
							 | 
						|
								            for (var i = 0; i < length; i++) array[i] = pool[NumberUtility.Random(0, max)];
							 | 
						|
								            return new string(array);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>对字符串列表去重。指定 valid 参数时将去除无效字符串。</summary>
							 | 
						|
								        /// <param name="strings"></param>
							 | 
						|
								        /// <param name="valid"></param>
							 | 
						|
								        public static string[] Distinct(IEnumerable<string> strings, bool valid = false)
							 | 
						|
								        {
							 | 
						|
								            if (strings == null) return new string[0];
							 | 
						|
								
							 | 
						|
								            const string space = " ";
							 | 
						|
								            var hasNull = false;
							 | 
						|
								            var hasEmpty = false;
							 | 
						|
								            var hasSpace = false;
							 | 
						|
								
							 | 
						|
								            var array = new ArrayBuilder<string>();
							 | 
						|
								            foreach (var s in strings)
							 | 
						|
								            {
							 | 
						|
								                if (s == null)
							 | 
						|
								                {
							 | 
						|
								                    if (valid) continue;
							 | 
						|
								                    if (hasNull) continue;
							 | 
						|
								                    hasNull = true;
							 | 
						|
								                    array.Add(s);
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								                if (s == Empty)
							 | 
						|
								                {
							 | 
						|
								                    if (valid) continue;
							 | 
						|
								                    if (hasEmpty) continue;
							 | 
						|
								                    hasEmpty = true;
							 | 
						|
								                    array.Add(s);
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								                if (s == space)
							 | 
						|
								                {
							 | 
						|
								                    if (valid) continue;
							 | 
						|
								                    if (hasSpace) continue;
							 | 
						|
								                    hasSpace = true;
							 | 
						|
								                    array.Add(s);
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                var exist = false;
							 | 
						|
								                for (var i = 0; i < array.Length; i++)
							 | 
						|
								                {
							 | 
						|
								                    if (array[i] == s)
							 | 
						|
								                    {
							 | 
						|
								                        exist = true;
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								                if (exist) continue;
							 | 
						|
								
							 | 
						|
								                array.Add(s);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return array.Export();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>约束字符串中的字符,只包含指定的字符。</summary>
							 | 
						|
								        public static string Restrict(string text, char[] chars)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text)) return Empty;
							 | 
						|
								            if (chars == null || chars.Length < 1) return Empty;
							 | 
						|
								
							 | 
						|
								            var total = text.Length;
							 | 
						|
								            var count = chars.Length;
							 | 
						|
								            var array = new char[total];
							 | 
						|
								            var added = 0;
							 | 
						|
								            for (var i = 0; i < total; i++)
							 | 
						|
								            {
							 | 
						|
								                var c = text[i];
							 | 
						|
								                for (var j = 0; j < count; j++)
							 | 
						|
								                {
							 | 
						|
								                    if (c == chars[j])
							 | 
						|
								                    {
							 | 
						|
								                        array[added] = c;
							 | 
						|
								                        added += 1;
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            if (added < 1) return Empty;
							 | 
						|
								            return new string(array, 0, added);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>约束字符串中的字符,只包含指定的字符。</summary>
							 | 
						|
								        public static string Restrict(string text, string chars) => IsEmpty(text) || IsEmpty(chars) ? Empty : Restrict(text, chars.ToCharArray());
							 | 
						|
								
							 | 
						|
								        /// <summary>约束字符串中的字符,只包含字母。</summary>
							 | 
						|
								        public static string RestrictLetters(string text) => Restrict(text, LetterChars.ToCharArray());
							 | 
						|
								
							 | 
						|
								        /// <summary>约束字符串中的字符,只包含数字。</summary>
							 | 
						|
								        public static string RestrictNumeric(string text) => Restrict(text, NumericChars.ToCharArray());
							 | 
						|
								
							 | 
						|
								        /// <summary>返回此字符串的安全键副本,只保留数据记录主键中可能出现的字符,默认限制长度为 255 字符。</summary>
							 | 
						|
								        public static string SafeKey(string text, int maxLength = 255)
							 | 
						|
								        {
							 | 
						|
								            if (string.IsNullOrEmpty(text)) return Empty;
							 | 
						|
								            var input = text;
							 | 
						|
								
							 | 
						|
								            var max = maxLength;
							 | 
						|
								            if (max < 1 || max > input.Length) max = input.Length;
							 | 
						|
								
							 | 
						|
								            // 允许用于主键值的字符。
							 | 
						|
								            const string KeyCollection = "-_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
							 | 
						|
								
							 | 
						|
								            var sb = new StringBuilder();
							 | 
						|
								            var total = input.Length;
							 | 
						|
								            var length = 0;
							 | 
						|
								            for (var i = 0; i < total; i++)
							 | 
						|
								            {
							 | 
						|
								                var c = input[i];
							 | 
						|
								                if (KeyCollection.IndexOf(c) < 0) continue;
							 | 
						|
								                sb.Append(c);
							 | 
						|
								                length += 1;
							 | 
						|
								                if (length >= max) break;
							 | 
						|
								            }
							 | 
						|
								            var result = sb.ToString();
							 | 
						|
								            if (result.Length > max) result = result.Substring(0, max);
							 | 
						|
								            return result;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>追加字符串。</summary>
							 | 
						|
								        public static StringBuilder Append(StringBuilder builder, params object[] cells)
							 | 
						|
								        {
							 | 
						|
								            if (builder != null) builder.Append(Join(null, cells));
							 | 
						|
								            return builder;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>对 URL 编码。</summary>
							 | 
						|
								        public static string EncodeUrl(string plain)
							 | 
						|
								        {
							 | 
						|
								            return UrlEncoding.Encode(plain);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>对 URL 解码。</summary>
							 | 
						|
								        public static string DecodeUrl(string escaped)
							 | 
						|
								        {
							 | 
						|
								            return UrlEncoding.Decode(escaped);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>返回此字符串转换为小写形式的副本。</summary>
							 | 
						|
								        public static string Lower(string text)
							 | 
						|
								        {
							 | 
						|
								            if (text == null) return null;
							 | 
						|
								            else if (text.Length < 1) return Empty;
							 | 
						|
								            else return text.ToLower();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>返回此字符串转换为大写形式的副本。</summary>
							 | 
						|
								        public static string Upper(string text)
							 | 
						|
								        {
							 | 
						|
								            if (text == null) return null;
							 | 
						|
								            else if (text.Length < 1) return Empty;
							 | 
						|
								            else return text.ToUpper();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>检查中国手机号码,包含 13x、14x、15x、16x、17x、18x 和 19x 号段。</summary>
							 | 
						|
								        public static bool IsPhone(string phone)
							 | 
						|
								        {
							 | 
						|
								            if (string.IsNullOrEmpty(phone)) return false;
							 | 
						|
								            var regex = new Regex(@"^(13|14|15|16|17|18|19)\d{9}$", RegexOptions.None);
							 | 
						|
								            var match = regex.Match(phone);
							 | 
						|
								            return match.Success;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>渲染 Markdown 文本为 HTML 文本。</summary>
							 | 
						|
								        public static string RenderMarkdown(string markdown) => MarkdownSharp.Demo.ToHtml(markdown);
							 | 
						|
								
							 | 
						|
								        /// <summary>合并用于启动进程的参数。</summary>
							 | 
						|
								        public static string MergeProcessArgument(params object[] args)
							 | 
						|
								        {
							 | 
						|
								            // var special = " \"\n\r\b\t\f";
							 | 
						|
								
							 | 
						|
								            var list = new List<string>();
							 | 
						|
								            if (args != null)
							 | 
						|
								            {
							 | 
						|
								                foreach (var i in args)
							 | 
						|
								                {
							 | 
						|
								                    var arg = null as string;
							 | 
						|
								                    if (i != null)
							 | 
						|
								                    {
							 | 
						|
								                        if (i is string) arg = i as string;
							 | 
						|
								                        else arg = i.ToString();
							 | 
						|
								                    }
							 | 
						|
								
							 | 
						|
								                    if (string.IsNullOrEmpty(arg))
							 | 
						|
								                    {
							 | 
						|
								                        list.Add("\"\"");
							 | 
						|
								                        continue;
							 | 
						|
								                    }
							 | 
						|
								                    if (arg.Contains(" ") || arg.Contains("\""))
							 | 
						|
								                    {
							 | 
						|
								                        list.Add(Merge("\"", arg.Replace("\"", "\\\""), "\""));
							 | 
						|
								                        continue;
							 | 
						|
								                    }
							 | 
						|
								                    list.Add(arg);
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            var result = Join(" ", list.ToArray());
							 | 
						|
								            return result;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>合并用于启动进程的参数。</summary>
							 | 
						|
								        private static string MergeProcessArgument_2(params object[] args)
							 | 
						|
								        {
							 | 
						|
								            if (args == null) return "";
							 | 
						|
								            if (args.Length < 1) return "";
							 | 
						|
								
							 | 
						|
								            var sb = new StringBuilder();
							 | 
						|
								            for (var i = 0; i < args.Length; i++)
							 | 
						|
								            {
							 | 
						|
								                if (i > 0) sb.Append(" ");
							 | 
						|
								
							 | 
						|
								                var arg = null as string;
							 | 
						|
								                if (args[i] != null)
							 | 
						|
								                {
							 | 
						|
								                    if (args[i] is string) arg = args[i] as string;
							 | 
						|
								                    else arg = args[i].ToString();
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                if (arg.IsEmpty())
							 | 
						|
								                {
							 | 
						|
								                    sb.Append("\"\"");
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // var special = " \"\n\r\b\t\f";
							 | 
						|
								                var special = " \"";
							 | 
						|
								                if (arg.IndexOfAny(special.ToCharArray()) < 0)
							 | 
						|
								                {
							 | 
						|
								                    sb.Append(arg);
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    sb.Append("\"");
							 | 
						|
								                    if (arg.NotEmpty())
							 | 
						|
								                    {
							 | 
						|
								                        foreach (var c in arg)
							 | 
						|
								                        {
							 | 
						|
								                            switch (c)
							 | 
						|
								                            {
							 | 
						|
								                                case '"':
							 | 
						|
								                                    sb.Append("\\\"");
							 | 
						|
								                                    break;
							 | 
						|
								                                // case '\n':
							 | 
						|
								                                //     sb.Append("\\n");
							 | 
						|
								                                //     break;
							 | 
						|
								                                // case '\r':
							 | 
						|
								                                //     sb.Append("\\r");
							 | 
						|
								                                //     break;
							 | 
						|
								                                // case '\b':
							 | 
						|
								                                //     sb.Append("\\b");
							 | 
						|
								                                //     break;
							 | 
						|
								                                // case '\t':
							 | 
						|
								                                //     sb.Append("\\t");
							 | 
						|
								                                //     break;
							 | 
						|
								                                default:
							 | 
						|
								                                    sb.Append(c);
							 | 
						|
								                                    break;
							 | 
						|
								                            }
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                    sb.Append("\"");
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            var result = sb.ToString();
							 | 
						|
								            return result;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>字符串仅使用英文。可指定空字符串的返回值。</summary>
							 | 
						|
								        public static bool IsEnglish(string text, bool ifEmpty = true)
							 | 
						|
								        {
							 | 
						|
								            if (string.IsNullOrEmpty(text)) return ifEmpty;
							 | 
						|
								            var trim = text.Trim();
							 | 
						|
								            if (string.IsNullOrEmpty(trim)) return ifEmpty;
							 | 
						|
								            return Regex.IsMatch(trim, "(^[0-9a-zA-Z_ -;:,~!@#%&=<>~\\(\\)\\.\\$\\^\\`\\'\\\"\\&\\{\\}\\[\\]\\|\\*\\+\\?]{0,80}$)");
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>转换文本为驼峰形式。</summary>
							 | 
						|
								        public static string Camel(string text)
							 | 
						|
								        {
							 | 
						|
								            if (string.IsNullOrEmpty(text) || !char.IsUpper(text[0])) return text;
							 | 
						|
								
							 | 
						|
								            var chars = text.ToCharArray();
							 | 
						|
								            for (int i = 0; i < chars.Length; i++)
							 | 
						|
								            {
							 | 
						|
								                if (i == 1 && !char.IsUpper(chars[i])) break;
							 | 
						|
								
							 | 
						|
								                bool hasNext = (i + 1) < chars.Length;
							 | 
						|
								                if (i > 0 && hasNext)
							 | 
						|
								                {
							 | 
						|
								                    var nextChar = chars[i + 1];
							 | 
						|
								                    if (!char.IsUpper(nextChar))
							 | 
						|
								                    {
							 | 
						|
								                        if (char.IsSeparator(nextChar)) chars[i] = char.ToLowerInvariant(chars[i]);
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								                chars[i] = char.ToLowerInvariant(chars[i]);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return new string(chars);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>移除参数 chars 中的每一个字符。</summary>
							 | 
						|
								        public static string RemoveChars(string text, string chars)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text)) return Empty;
							 | 
						|
								            if (IsEmpty(chars)) return text;
							 | 
						|
								            return RemoveChar(text, chars.ToCharArray());
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>移除指定的一个或多个字符。</summary>
							 | 
						|
								        public static string RemoveChar(string text, params char[] chars)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text)) return Empty;
							 | 
						|
								            if (chars == null || chars.Length < 1) return text;
							 | 
						|
								
							 | 
						|
								            var length = text.Length;
							 | 
						|
								            var array = new char[length];
							 | 
						|
								            var count = chars.Length;
							 | 
						|
								
							 | 
						|
								            var added = 0;
							 | 
						|
								            for (var i = 0; i < length; i++)
							 | 
						|
								            {
							 | 
						|
								                var c = text[i];
							 | 
						|
								                var removed = false;
							 | 
						|
								                for (var j = 0; j < count; j++)
							 | 
						|
								                {
							 | 
						|
								                    if (c == chars[j])
							 | 
						|
								                    {
							 | 
						|
								                        removed = true;
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								                if (removed) continue;
							 | 
						|
								                array[added] = c;
							 | 
						|
								                added += 1;
							 | 
						|
								            }
							 | 
						|
								            if (added < 1) return Empty;
							 | 
						|
								            return new string(array, 0, added);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>防注入,去除常见的功能符号。可限定字符串长度。</summary>
							 | 
						|
								        public static string AntiInject(string text, int length = -1, string chars = "\"'`\b\f\n\r\t\\/:*?<>|@")
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text) || length == 0) return Empty;
							 | 
						|
								
							 | 
						|
								            var t = Trim(text);
							 | 
						|
								            t = RemoveChars(t, chars);
							 | 
						|
								            if (length > 0 && t.Length > length) t = t.Substring(0, length);
							 | 
						|
								            return t;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>获取指定长度的字符串片段,可指定 trim 参数对片段再次修剪。</summary>
							 | 
						|
								        public static string Left(string text, int maxLength, bool trim = false, bool trimBlank = false)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text)) return Empty;
							 | 
						|
								            if (maxLength > 0 && text.Length > maxLength)
							 | 
						|
								            {
							 | 
						|
								                var left = text.Substring(0, maxLength);
							 | 
						|
								                return trim ? Trim(left, trimBlank) : left;
							 | 
						|
								            }
							 | 
						|
								            else return trim ? Trim(text, trimBlank) : text;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>获取指定长度的字符串片段,可指定 trim 参数对片段再次修剪。</summary>
							 | 
						|
								        public static string Right(string text, int maxLength, bool trim = false, bool trimBlank = false)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text)) return Empty;
							 | 
						|
								            if (maxLength > 0 && text.Length > maxLength)
							 | 
						|
								            {
							 | 
						|
								                var left = text.Substring(text.Length - maxLength);
							 | 
						|
								                return trim ? Trim(left, trimBlank) : left;
							 | 
						|
								            }
							 | 
						|
								            else return trim ? Trim(text, trimBlank) : text;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>获取字符串片段,起始位置从 0 开始,可指定 trim 参数对片段再次修剪。</summary>
							 | 
						|
								        /// <exception cref="ArgumentOutOfRangeException"></exception>
							 | 
						|
								        public static string Middle(string text, int startIndex, int maxLength = -1, bool trim = false, bool trimBlank = false)
							 | 
						|
								        {
							 | 
						|
								            if (IsEmpty(text) || maxLength == 0) return Empty;
							 | 
						|
								            var total = text.Length;
							 | 
						|
								            var start = startIndex;
							 | 
						|
								            var length = maxLength;
							 | 
						|
								            if (start < 0)
							 | 
						|
								            {
							 | 
						|
								                length = length + start;
							 | 
						|
								                start = 0;
							 | 
						|
								            }
							 | 
						|
								            if (maxLength < 0) length = total;
							 | 
						|
								            if (start + length > total) length = total - start;
							 | 
						|
								            if (start == 0 && length == total) return trim ? Trim(text, trimBlank) : text;
							 | 
						|
								
							 | 
						|
								            var middle = text.Substring(start, length);
							 | 
						|
								            return trim ? Trim(middle, trimBlank) : middle;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        #region Lock
							 | 
						|
								
							 | 
						|
								        static TextLocker _locker = new TextLocker();
							 | 
						|
								
							 | 
						|
								        /// <summary>锁定文本,在锁中执行函数。</summary>
							 | 
						|
								        /// <param name="text">要锁定的文本。</param>
							 | 
						|
								        /// <param name="inLock">要在锁中执行的函数。</param>
							 | 
						|
								        /// <exception cref="ArgumentNullException"></exception>
							 | 
						|
								        public static T Lock<T>(this string text, Func<T> inLock)
							 | 
						|
								        {
							 | 
						|
								            if (inLock == null) throw new ArgumentNullException(nameof(inLock));
							 | 
						|
								            return _locker.InLock(text, inLock);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>锁定文本,在锁中执行函数。</summary>
							 | 
						|
								        /// <param name="text">要锁定的文本。</param>
							 | 
						|
								        /// <param name="inLock">要在锁中执行的函数。</param>
							 | 
						|
								        /// <exception cref="ArgumentNullException"></exception>
							 | 
						|
								        public static void Lock(this string text, Action inLock)
							 | 
						|
								        {
							 | 
						|
								            if (inLock == null) throw new ArgumentNullException(nameof(inLock));
							 | 
						|
								            _locker.InLock(text, inLock);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        #endregion
							 | 
						|
								
							 | 
						|
								        #region encoding
							 | 
						|
								
							 | 
						|
								        /// <summary>检查字节数组包含 UTF-8 BOM 头。</summary>
							 | 
						|
								        public static bool ContainsBOM(byte[] bytes)
							 | 
						|
								        {
							 | 
						|
								            if (bytes == null) return false;
							 | 
						|
								            if (bytes.LongLength < 3L) return false;
							 | 
						|
								            return bytes[0L] == 0xEF && bytes[1L] == 0xBB && bytes[2L] == 0xBF;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>检查字节数组是 UTF-8 文本。可指定检查的最大字节长度。</summary>
							 | 
						|
								        /// <param name="bytes">要检查的字节数组。</param>
							 | 
						|
								        /// <param name="offset">已检查的偏移量。</param>
							 | 
						|
								        /// <param name="checkLength">检查的最大字节长度。</param>
							 | 
						|
								        public static bool IsUTF8(byte[] bytes, Class<int> offset, int checkLength = 1048576)
							 | 
						|
								        {
							 | 
						|
								            return IsUTF8(bytes, offset, checkLength);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>检查字节数组是 UTF-8 文本,默认最多检测 1MB 数据。</summary>
							 | 
						|
								        /// <param name="bytes">要检查的字节数组。</param>
							 | 
						|
								        /// <param name="checkLength">检查的最大字节长度,指定为 0 将不限制检查长度。</param>
							 | 
						|
								        /// <param name="offset">已检查的偏移量,用于调试。</param>
							 | 
						|
								        public static bool IsUTF8(byte[] bytes, int checkLength = 1048576, Class<int> offset = null)
							 | 
						|
								        {
							 | 
						|
								            // UTF8在Unicode的基础上制定了这样一套规则:
							 | 
						|
								            // 1.对于单字节字符,比特位的最高位为0;
							 | 
						|
								            // 2.对于多字节字符,第一个字节的比特位中,最高位有n个1,剩下的n - 1个字节的比特位中,最高位都是10。
							 | 
						|
								            // 好了,我知道你一定看不懂,那就先来看看下面例子后,再去看上面定义吧。
							 | 
						|
								            // 比如一个字符(“A”),它在UTF8中的编码为(用二进制表示):01000001。由于比特位的最高位是0,表示它是单字节,它只需要1个字节就可以表示。
							 | 
						|
								            // 再比如一个字符(“判”),它在UTF8中的编码为(用二进制表示):11100101 10001000 10100100。由于在第一个字节中,比特位最高位有3个1,说明这个字符总共需要3个字节来表示,且后3 - 1 = 2位字节中,比特位的最高位为10。
							 | 
						|
								
							 | 
						|
								            if (bytes == null) return false;
							 | 
						|
								            var length = bytes.LongLength;
							 | 
						|
								
							 | 
						|
								            // 检查 BOM 头。
							 | 
						|
								            if (ContainsBOM(bytes)) return true;
							 | 
						|
								
							 | 
						|
								            var hasOffset = offset != null;
							 | 
						|
								
							 | 
						|
								            var append = 0;
							 | 
						|
								            if (hasOffset) offset.Value = 0;
							 | 
						|
								            for (int i = 0; i < length; i++)
							 | 
						|
								            {
							 | 
						|
								                if (checkLength > 0 && i >= checkLength) break;
							 | 
						|
								
							 | 
						|
								                var b = bytes[i];
							 | 
						|
								                if (hasOffset) offset.Value = i;
							 | 
						|
								
							 | 
						|
								                // 追加字节最高位为 0。
							 | 
						|
								                if (append > 0)
							 | 
						|
								                {
							 | 
						|
								                    if (b >> 6 != 2) return false;
							 | 
						|
								                    append -= 1;
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // ASCII 字符。
							 | 
						|
								                if (b < 128) continue;
							 | 
						|
								
							 | 
						|
								                // 2 字节 UTF-8。
							 | 
						|
								                if (b >= 0xC0 && b <= 0xDF)
							 | 
						|
								                {
							 | 
						|
								                    append = 1;
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // 3 字节 UTF-8 字符。
							 | 
						|
								                if (b >= 0xE0 && b <= 0xEF)
							 | 
						|
								                {
							 | 
						|
								                    append = 2;
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // 4 字节 UTF-8 字符。
							 | 
						|
								                if (b >= 0xF0 && b <= 0xF7)
							 | 
						|
								                {
							 | 
						|
								                    append = 3;
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // 5 字节 UTF-8 字符。
							 | 
						|
								                if (b >= 0xF8 && b <= 0xFB)
							 | 
						|
								                {
							 | 
						|
								                    append = 4;
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // 6 字节 UTF-8 字符。
							 | 
						|
								                if (b >= 0xFC && b <= 0xFD)
							 | 
						|
								                {
							 | 
						|
								                    append = 5;
							 | 
						|
								                    continue;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // 未知字节,非 UTF-8 定义。
							 | 
						|
								                return false;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return true;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        /// <summary>解析编码名称。</summary>
							 | 
						|
								        /// <returns>解析失败时,返回 NULL 值。</returns>
							 | 
						|
								        private static Encoding ParseEncoding(string encoding)
							 | 
						|
								        {
							 | 
						|
								            if (encoding.IsEmpty()) return null;
							 | 
						|
								
							 | 
						|
								            var lower = encoding.Lower();
							 | 
						|
								            var nick = lower.Replace("-", "");
							 | 
						|
								            switch (nick)
							 | 
						|
								            {
							 | 
						|
								                case "ascii":
							 | 
						|
								                    return Encoding.ASCII;
							 | 
						|
								                case "bigendia":
							 | 
						|
								                case "bigendianunicode":
							 | 
						|
								                    return Encoding.BigEndianUnicode;
							 | 
						|
								                case "utf7":
							 | 
						|
								                    return Encoding.UTF7;
							 | 
						|
								                case "utf8":
							 | 
						|
								                    return Encoding.UTF8;
							 | 
						|
								                case "utf16":
							 | 
						|
								                case "unicode":
							 | 
						|
								                    return Encoding.Unicode;
							 | 
						|
								                case "utf32":
							 | 
						|
								                    return Encoding.UTF7;
							 | 
						|
								
							 | 
						|
								                case "default":
							 | 
						|
								                    return Encoding.Default;
							 | 
						|
								
							 | 
						|
								                case "ansi":
							 | 
						|
								                case "gb2312":
							 | 
						|
								                case "gb18030":
							 | 
						|
								                    return Encoding.Default;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return null;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        #endregion
							 | 
						|
								
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								}
							 | 
						|
								
							 |