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.

650 lines
24 KiB

  1. using Apewer.Internals;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Data;
  5. using System.IO;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. namespace Apewer
  9. {
  10. /// <summary>文本实用工具。</summary>
  11. public class TextUtility
  12. {
  13. /// <summary>UTF-8 BOM。</summary>
  14. public static readonly byte[] Bom = Constant.Bom;
  15. /// <summary>空文本。</summary>
  16. public const string EmptyString = Constant.EmptyString;
  17. /// <summary>合并为字符串。</summary>
  18. public static string Merge(params object[] cells)
  19. {
  20. return Join(null, cells);
  21. }
  22. /// <summary>合并为字符串。</summary>
  23. public static string Merge(IEnumerable<object> cells)
  24. {
  25. return Join(null, (IEnumerable<object>)cells);
  26. }
  27. /// <summary>合并为字符串。</summary>
  28. public static string Join(string separator, params object[] cells)
  29. {
  30. return Join(separator, (IEnumerable<object>)cells);
  31. }
  32. /// <summary>合并为字符串。</summary>
  33. public static string Join(string separator, IEnumerable<object> cells)
  34. {
  35. if (cells == null) return Constant.EmptyString;
  36. var sb = new StringBuilder();
  37. var first = true;
  38. var hasSeparator = !string.IsNullOrEmpty(separator);
  39. foreach (var cell in cells)
  40. {
  41. // if (cell == null) continue;
  42. if (!first && hasSeparator) sb.Append(separator);
  43. first = false;
  44. if (cell == null) continue;
  45. var text = (cell is string) ? (string)cell : cell.ToString();
  46. if (string.IsNullOrEmpty(text)) continue;
  47. sb.Append(cell.ToString());
  48. }
  49. var result = sb.ToString();
  50. return result;
  51. }
  52. /// <summary>重复指定子字符串,直到达到指定长度。</summary>
  53. /// <param name="cell">子字符串。</param>
  54. /// <param name="length">目标字符串的长度。</param>
  55. public static string CopyChar(string cell, int length)
  56. {
  57. return TextGenerator.CopyChar(cell, length);
  58. }
  59. /// <summary>获取指定长的的空格。</summary>
  60. public static string Space(int length)
  61. {
  62. return TextGenerator.Space(length);
  63. }
  64. /// <summary>将文本以转换为字节数组。默认 Encoding 为 UTF-8。</summary>
  65. public static byte[] ToBinary(string text, Encoding encoding = null)
  66. {
  67. return TextConverter.ToBinary(text, encoding ?? Encoding.UTF8);
  68. }
  69. /// <summary>将字节数组转换为文本。默认 Encoding 为 UTF-8。</summary>
  70. public static string FromBinary(byte[] bytes, Encoding encoding = null)
  71. {
  72. if (bytes == null) return Constant.EmptyString;
  73. if (bytes.LongLength < 1L) return Constant.EmptyString;
  74. try
  75. {
  76. if (encoding == null) return FromBinary(bytes, Encoding.UTF8);
  77. return encoding.GetString(bytes);
  78. }
  79. catch { return Constant.EmptyString; }
  80. }
  81. /// <summary>将明文文本以 UTF-8 转换为 Base64 文本。</summary>
  82. public static string ToBase64(string plain)
  83. {
  84. return TextConverter.ToBase64(plain);
  85. }
  86. /// <summary>将 Base64 文本以 UTF-8 转换为明文文本。</summary>
  87. public static string FromBase64(string cipher)
  88. {
  89. return TextConverter.FromBase64(cipher);
  90. }
  91. /// <summary>byte -> plain</summary>
  92. public static string EncodeByte(byte @byte)
  93. {
  94. return TextConverter.EncodeByte(@byte);
  95. }
  96. /// <summary>binary -> hex plain</summary>
  97. public static string EncodeBinary(byte[] bytes)
  98. {
  99. return TextConverter.EncodeBinary(bytes);
  100. }
  101. /// <summary>hex text -> plain</summary>
  102. public static string EncodeText(string text, bool delimiter = false)
  103. {
  104. return TextConverter.EncodeText(text, delimiter);
  105. }
  106. /// <summary>hex plain -> binary</summary>
  107. public static byte[] DecodeBinary(string plain)
  108. {
  109. return TextConverter.DecodeBinary(plain);
  110. }
  111. /// <summary>hex plain -> text</summary>
  112. public static string DecodeText(string plain)
  113. {
  114. return TextConverter.DecodeText(plain);
  115. }
  116. /// <summary>将字节数组格式化为字符串。</summary>
  117. public static string FormatX2(params byte[] bytes)
  118. {
  119. return TextConverter.FormatX2(bytes);
  120. }
  121. /// <summary>获取单精度浮点对象。</summary>
  122. public static Single GetFloat(char origin)
  123. {
  124. return TextConverter.GetSingle(origin.ToString());
  125. }
  126. /// <summary>获取单精度浮点对象。</summary>
  127. public static Single GetFloat(string origin)
  128. {
  129. return TextConverter.GetSingle(origin);
  130. }
  131. /// <summary>获取单精度浮点对象。</summary>
  132. public static Single GetSingle(char origin)
  133. {
  134. return TextConverter.GetSingle(origin.ToString());
  135. }
  136. /// <summary>获取单精度浮点对象。</summary>
  137. public static Single GetSingle(string origin)
  138. {
  139. return TextConverter.GetSingle(origin);
  140. }
  141. /// <summary>获取双精度浮点对象。</summary>
  142. public static Double GetDouble(char origin)
  143. {
  144. return TextConverter.GetDouble(origin.ToString());
  145. }
  146. /// <summary>获取双精度浮点对象。</summary>
  147. public static Double GetDouble(string origin)
  148. {
  149. return TextConverter.GetDouble(origin);
  150. }
  151. /// <summary>获取 Decimal 对象。</summary>
  152. public static decimal GetDecimal(char origin)
  153. {
  154. return TextConverter.GetDecimal(origin.ToString());
  155. }
  156. /// <summary>获取 Decimal 对象。</summary>
  157. public static decimal GetDecimal(string origin)
  158. {
  159. return TextConverter.GetDecimal(origin);
  160. }
  161. /// <summary>获取 Int16 对象。</summary>
  162. public static Int16 GetInt16(char origin)
  163. {
  164. return TextConverter.GetInt16(origin.ToString());
  165. }
  166. /// <summary>获取 Int16 对象。</summary>
  167. public static Int16 GetInt16(string origin)
  168. {
  169. return TextConverter.GetInt16(origin);
  170. }
  171. /// <summary>获取 Int32 对象。</summary>
  172. public static Int32 GetInt32(char origin)
  173. {
  174. return TextConverter.GetInt32(origin.ToString());
  175. }
  176. /// <summary>获取 Int32 对象。</summary>
  177. public static Int32 GetInt32(string origin)
  178. {
  179. return TextConverter.GetInt32(origin);
  180. }
  181. /// <summary>获取 Int64 对象。</summary>
  182. public static Int64 GetInt64(char origin)
  183. {
  184. return TextConverter.GetInt64(origin.ToString());
  185. }
  186. /// <summary>获取 Int64 对象。</summary>
  187. public static Int64 GetInt64(string origin)
  188. {
  189. return TextConverter.GetInt64(origin);
  190. }
  191. /// <summary>为字符串前添加字符“0”。</summary>
  192. /// <param name="origin">原字符串,内容应为整数、小数或十六进制数,若格式不符则返回原字符串。</param>
  193. /// <param name="length">新字符串的长度,若大于原数字长度,则不添加额外的“0”。</param>
  194. public static string PreZero(string origin, int length = 0)
  195. {
  196. return TextModifier.PreZero(origin, length);
  197. }
  198. /// <summary>删除字符串前额外的字符“0”。</summary>
  199. public static string RemoveZero(string argValue)
  200. {
  201. return TextModifier.RemoveZero(argValue);
  202. }
  203. /// <summary>替换父字符串中的子字符串。</summary>
  204. /// <param name="parent">父字符串。</param>
  205. /// <param name="new">新子字符串,保留大小写。</param>
  206. /// <param name="old">原子字符串。</param>
  207. /// <param name="ignoreCase">查找时是否忽略父字符串和原子字符串大小写。</param>
  208. /// <returns>替换后的父字符串。</returns>
  209. public static string Replace(string parent, string old, string @new, bool ignoreCase = false)
  210. {
  211. return TextModifier.Replace(parent, old, @new, ignoreCase);
  212. }
  213. /// <summary>修复文本后缀。默认用于修复 Windows 目录路径。</summary>
  214. /// <param name="origin">原文本。</param>
  215. /// <param name="include">True:追加指定后缀;False:去除指定后缀。</param>
  216. /// <param name="foot">后缀文本。</param>
  217. public static string AssureEnds(string origin, bool include = true, string foot = "\\")
  218. {
  219. return TextModifier.AssureEnds(origin, include, foot);
  220. }
  221. /// <summary>用单字符作为分隔符拆分文本。</summary>
  222. public static string[] Split(string text, char separator)
  223. {
  224. if (text == null) return new string[0];
  225. if (text.Length < 1) return new string[] { "" };
  226. if ((object)separator == null) return new string[] { text };
  227. return text.Split(separator);
  228. }
  229. /// <summary>用字符串作为分隔符拆分文本。</summary>
  230. public static string[] Split(string text, string separator)
  231. {
  232. if (text == null) return new string[0];
  233. if (text.Length < 1) return new string[] { "" };
  234. if (string.IsNullOrEmpty(separator)) return new string[] { text };
  235. if (separator.Length > text.Length) return new string[] { text };
  236. var list = new List<string>();
  237. var position = 0;
  238. var total = text.Length;
  239. var length = separator.Length;
  240. var cell = new StringBuilder();
  241. while (position < total)
  242. {
  243. var read = null as string;
  244. if (position + length < total) read = text.Substring(position, length);
  245. else read = text.Substring(position);
  246. if (read == separator)
  247. {
  248. if (cell.Length > 0)
  249. {
  250. list.Add(cell.ToString());
  251. // cell.Clear();
  252. cell = new StringBuilder();
  253. }
  254. else
  255. {
  256. list.Add("");
  257. }
  258. position += length;
  259. }
  260. else
  261. {
  262. cell.Append((char)text[position]);
  263. position += 1;
  264. }
  265. if (position >= total)
  266. {
  267. list.Add(cell.ToString());
  268. }
  269. }
  270. var array = list.ToArray();
  271. return array;
  272. }
  273. /// <summary>用多个分隔符拆分文本。</summary>
  274. public static string[] Split(string text, params char[] separators)
  275. {
  276. if (text == null) return new string[0];
  277. if (text.Length < 1) return new string[] { "" };
  278. if (separators == null || separators.Length < 1) return new string[] { text };
  279. if (separators.Length == 1) return Split(text, separators[0]);
  280. var list = new List<string>();
  281. var separatorsText = new string(separators);
  282. var sb = new StringBuilder();
  283. foreach (var c in text)
  284. {
  285. if (separatorsText.IndexOf(c) >= 0)
  286. {
  287. list.Add(sb.ToString());
  288. //sb.Clear();
  289. sb = new StringBuilder();
  290. continue;
  291. }
  292. sb.Append(c);
  293. }
  294. list.Add(sb.ToString());
  295. #if !NET20
  296. sb.Clear();
  297. #endif
  298. return list.ToArray();
  299. }
  300. /// <summary>移除字符串前后的空白。</summary>
  301. /// <param name="origin">原始字符串。</param>
  302. public static string Trim(string origin)
  303. {
  304. return TextModifier.Trim(origin);
  305. }
  306. /// <summary>移除字符串前后的空白。</summary>
  307. /// <param name="origin">原始字符串。</param>
  308. /// <param name="allCases">所有情况,全角空格将被去除。</param>
  309. public static string Trim(string origin, bool allCases)
  310. {
  311. return TextModifier.Trim(origin, allCases);
  312. }
  313. /// <summary>防注入处理,去除会引发代码注入的字符。可限定字符串长度。</summary>
  314. public static string AntiInject(string text, int length, params char[] blacklist)
  315. {
  316. return TextModifier.AntiInject(text, -1, blacklist);
  317. }
  318. /// <summary>防注入处理,去除会引发代码注入的字符。可限定字符串长度。</summary>
  319. public static string AntiInject(string text, int length, IEnumerable<char> blacklist)
  320. {
  321. return TextModifier.AntiInject(text, -1, blacklist);
  322. }
  323. /// <summary>防注入处理,去除会引发代码注入的字符。可限定字符串长度。</summary>
  324. public static string AntiInject(string text, int length = -1, string blacklist = Constant.InjectDefaultBlackList)
  325. {
  326. return TextModifier.AntiInject(text, -1, blacklist == null ? null : blacklist.ToCharArray());
  327. }
  328. /// <summary>剪取文本内容,若指定头部为空则从原文本首部起,若指定尾部为空则至原文本末尾。</summary>
  329. public static string Cut(string origin, string head = null, string foot = null)
  330. {
  331. return TextModifier.Cut(origin, head, foot);
  332. }
  333. /// <summary>比较两个字符串的相似度。返回值大于 0,小于等于 1。</summary>
  334. /// <param name="arg1"></param>
  335. /// <param name="arg2"></param>
  336. /// <returns></returns>
  337. public static double Similarity(string arg1, string arg2)
  338. {
  339. return Levenshtein.Compute(arg1, arg2).Rate;
  340. }
  341. /// <summary>判断对象为 Null、空字符串或空白字符串。</summary>
  342. public static bool IsEmpty(string text)
  343. {
  344. return TextVerifier.IsEmpty(text);
  345. }
  346. /// <summary>判断对象为含有内容的字符串。</summary>
  347. public static bool NotEmpty(string text)
  348. {
  349. return !TextVerifier.IsEmpty(text);
  350. }
  351. /// <summary>判断对象为 Null、空字符串或无实际内容的字符串。</summary>
  352. public static bool IsBlank(string text, bool allCases = false)
  353. {
  354. return TextVerifier.IsBlank(text, allCases);
  355. }
  356. /// <summary>判断对象为含有实际内容的字符串。</summary>
  357. public static bool NotBlank(string text, bool allCases = false)
  358. {
  359. return !TextVerifier.IsBlank(text, allCases);
  360. }
  361. /// <summary>生成新的 GUID(不带连字符、小写)。</summary>
  362. public static string NewGuid(bool hyphenation = false, bool lower = true)
  363. {
  364. var guid = Guid.NewGuid();
  365. if (!hyphenation && lower) return guid.ToString("n");
  366. var text = Guid.NewGuid().ToString();
  367. if (lower) text = text.ToLower();
  368. else text = text.ToUpper();
  369. if (!hyphenation) text = text.Replace("-", "");
  370. return text;
  371. }
  372. /// <summary>生成随机字符串,出现的字符由字符池指定,默认池包含数字和字母。</summary>
  373. /// <param name="pool">字符池,字符池中每个字符在随机字符串中出现的概率约等。</param>
  374. /// <param name="length">随机字符串的长度。</param>
  375. public static string Random(int length, string pool = "0123456789abcdefghijklmnopqrstuvwxyz")
  376. {
  377. return RandomHelper.RandomCustom(pool, length);
  378. }
  379. /// <summary>对字符串列表去重。指定 valid 参数时将去除 NULL、空字符串和空白字符串。</summary>
  380. public static List<string> Distinct(IEnumerable<string> origin, bool valid = false)
  381. {
  382. return TextModifier.Distinct(origin, valid);
  383. }
  384. /// <summary>约束字符串长度范围,超出的部分将被截取去除。</summary>
  385. public static string RestrictLength(string origin, int length)
  386. {
  387. return TextModifier.RestrictLength(origin, length);
  388. }
  389. /// <summary>约束字符串长度为 32,超出的部分将被截取去除。</summary>
  390. public static string Restrict32(string origin)
  391. {
  392. return TextModifier.RestrictLength(origin, 32);
  393. }
  394. /// <summary>约束字符串长度为 255,超出的部分将被截取去除。</summary>
  395. public static string Restrict255(string origin)
  396. {
  397. return TextModifier.RestrictLength(origin, 255);
  398. }
  399. /// <summary>约束字符串长度为 2000,超出的部分将被截取去除。</summary>
  400. public static string Restrict2000(string origin)
  401. {
  402. return TextModifier.RestrictLength(origin, 2000);
  403. }
  404. /// <summary>约束字符串中的字符,不允许的字符将被去除。</summary>
  405. public static string RestrictCharacters(string origin, params char[] allowable)
  406. {
  407. return TextModifier.RestrictCharacters(origin, new string(allowable));
  408. }
  409. /// <summary>约束字符串中的字符,不允许的字符将被去除。</summary>
  410. public static string RestrictCharacters(string origin, string allowable)
  411. {
  412. return TextModifier.RestrictCharacters(origin, allowable);
  413. }
  414. /// <summary>约束字符串中的字符,只保留字母。</summary>
  415. public static string RestrictLetters(string origin)
  416. {
  417. return TextModifier.RestrictCharacters(origin, Constant.LetterCollection);
  418. }
  419. /// <summary>约束字符串中的字符,只保留数字。</summary>
  420. public static string RestrictNumeric(string origin)
  421. {
  422. return TextModifier.RestrictCharacters(origin, Constant.NumberCollection);
  423. }
  424. /// <summary>约束字符串,只保留 GUID 可能出现的字符,根据连字符限定长度为 32 或 36。</summary>
  425. public static string RestrictGuid(string origin)
  426. {
  427. return TextModifier.RestrictGuid(origin);
  428. }
  429. /// <summary>追加字符串。</summary>
  430. public static void Append(StringBuilder builder, params object[] cells)
  431. {
  432. if (builder != null) builder.Append(Join(null, cells));
  433. }
  434. /// <summary>对 URL 编码。</summary>
  435. public static string EncodeUrl(string plain)
  436. {
  437. return UrlEncoding.Encode(plain);
  438. }
  439. /// <summary>对 URL 解码。</summary>
  440. public static string DecodeUrl(string escaped)
  441. {
  442. return UrlEncoding.Decode(escaped);
  443. }
  444. /// <summary>返回此字符串转换为小写形式的副本。</summary>
  445. public static string ToLower(string text)
  446. {
  447. if (text == null) return null;
  448. else if (text.Length < 1) return EmptyString;
  449. else return text.ToLower();
  450. }
  451. /// <summary>返回此字符串转换为大写形式的副本。</summary>
  452. public static string ToUpper(string text)
  453. {
  454. if (text == null) return null;
  455. else if (text.Length < 1) return EmptyString;
  456. else return text.ToUpper();
  457. }
  458. /// <summary>检查中国手机号码,包含 13x、14x、15x、16x、17x、18x 和 19x 号段。</summary>
  459. public static bool IsPhone(string phone)
  460. {
  461. if (string.IsNullOrEmpty(phone)) return false;
  462. var regex = new Regex(@"^(13|14|15|16|17|18|19)\d{9}$", RegexOptions.None);
  463. var match = regex.Match(phone);
  464. return match.Success;
  465. }
  466. /// <summary>合并用于启动进程的参数。</summary>
  467. public static string MergeProcessArgument(params object[] args)
  468. {
  469. // var special = " \"\n\r\b\t\f";
  470. var list = new List<string>();
  471. if (args != null)
  472. {
  473. foreach (var i in args)
  474. {
  475. var arg = null as string;
  476. if (i != null)
  477. {
  478. if (i is string) arg = i as string;
  479. else arg = i.ToString();
  480. }
  481. if (string.IsNullOrEmpty(arg))
  482. {
  483. list.Add("\"\"");
  484. continue;
  485. }
  486. if (arg.Contains(" ") || arg.Contains("\""))
  487. {
  488. list.Add(Merge("\"", arg.Replace("\"", "\\\""), "\""));
  489. continue;
  490. }
  491. list.Add(arg);
  492. }
  493. }
  494. var result = Join(" ", list.ToArray());
  495. return result;
  496. }
  497. /// <summary>合并用于启动进程的参数。</summary>
  498. private static string MergeProcessArgument_2(params object[] args)
  499. {
  500. if (args == null) return "";
  501. if (args.Length < 1) return "";
  502. var sb = new StringBuilder();
  503. for (var i = 0; i < args.Length; i++)
  504. {
  505. if (i > 0) sb.Append(" ");
  506. var arg = null as string;
  507. if (args[i] != null)
  508. {
  509. if (args[i] is string) arg = args[i] as string;
  510. else arg = args[i].ToString();
  511. }
  512. if (arg.IsEmpty())
  513. {
  514. sb.Append("\"\"");
  515. continue;
  516. }
  517. // var special = " \"\n\r\b\t\f";
  518. var special = " \"";
  519. if (arg.IndexOfAny(special.ToCharArray()) < 0)
  520. {
  521. sb.Append(arg);
  522. }
  523. else
  524. {
  525. sb.Append("\"");
  526. if (arg.NotEmpty())
  527. {
  528. foreach (var c in arg)
  529. {
  530. switch (c)
  531. {
  532. case '"':
  533. sb.Append("\\\"");
  534. break;
  535. // case '\n':
  536. // sb.Append("\\n");
  537. // break;
  538. // case '\r':
  539. // sb.Append("\\r");
  540. // break;
  541. // case '\b':
  542. // sb.Append("\\b");
  543. // break;
  544. // case '\t':
  545. // sb.Append("\\t");
  546. // break;
  547. default:
  548. sb.Append(c);
  549. break;
  550. }
  551. }
  552. }
  553. sb.Append("\"");
  554. }
  555. }
  556. var result = sb.ToString();
  557. return result;
  558. }
  559. }
  560. }