zoukankan      html  css  js  c++  java
  • C#字符串扩展方法【原创】

    StringEx

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Reflection;
      5 using System.Text;
      6 using System.Text.RegularExpressions;
      7 using NPOI.OpenXmlFormats.Spreadsheet;
      8 
      9 namespace Nutix.Extensions
     10 {
     11     public static class StringEx 
     12     {
     13         static StringEx()
     14         {
     15             StringEx.ResetParsers(false);
     16         }
     17 
     18         #region 1.Intercept :截取字符串
     19 
     20         /// <summary>
     21         /// 获取字符串中指定字符串之后的字符串
     22         /// </summary>
     23         /// <param name="str">要截取的原字符串</param>
     24         /// <param name="afterWhat">截取的依据</param>
     25         /// <returns>
     26         /// 返回截取到的字符串。
     27         /// 如果无任何匹配,则返回 null;
     28         /// </returns>
     29         public static string GetAfter(this string str, string afterWhat)
     30         {
     31             int index = str.IndexOf(afterWhat);
     32             if (index == -1) return null;
     33 
     34             index += str.Length;
     35             return str.Substring(index);
     36         }
     37 
     38         /// <summary>
     39         /// 获取字符串中指定字符串的最后一个匹配之后的字符串
     40         /// </summary>
     41         /// <param name="str">要截取的原字符串</param>
     42         /// <param name="afterWhat">截取的依据</param>
     43         /// <returns>
     44         /// 返回截取到的字符串。
     45         /// 如果无任何匹配,则返回 null;
     46         /// </returns>
     47         public static string GetLastAfter(this string str, string afterWhat)
     48         {
     49             int index = str.LastIndexOf(afterWhat);
     50             if (index == -1) return null;
     51 
     52             index += str.Length;
     53             return str.Substring(index);
     54         }
     55 
     56         /// <summary>
     57         /// 获取字符串中指定字符串之前的字符串
     58         /// </summary>
     59         /// <param name="str">要截取的原字符串</param>
     60         /// <param name="beforeWhat">截取的依据</param>
     61         /// <returns>
     62         /// 返回截取到的字符串。
     63         /// 如果无任何匹配,则返回 null;
     64         /// </returns>
     65         public static string GetBefore(this string str, string beforeWhat)
     66         {
     67             int index = str.IndexOf(beforeWhat);
     68             return str.Substring(0, index);
     69         }
     70 
     71         /// <summary>
     72         /// 获取字符串中指定字符串最后一个匹配之前的字符串
     73         /// </summary>
     74         /// <param name="str">要截取的原字符串</param>
     75         /// <param name="beforeWhat">截取的依据</param>
     76         /// <returns>
     77         /// 返回截取到的字符串。
     78         /// 如果无任何匹配,则返回 null;
     79         /// </returns>
     80         public static string GetLastBefore(this string str, string beforeWhat)
     81         {
     82             int index = str.LastIndexOf(beforeWhat);
     83             return str.Substring(0, index);
     84         }
     85 
     86         /// <summary>
     87         /// 获取字符串中指定的两个字符串之间的字符串内容
     88         /// </summary>
     89         /// <param name="str">要截取的原字符串</param>
     90         /// <param name="from">
     91         /// 截取时作为依据的起始字符串
     92         /// 如果 from == "",从零位置开始截取
     93         /// </param>
     94         /// <param name="to">
     95         /// 截取时作为依据的终止字符串
     96         /// 如果 to == "", 一直截取到最后一个字符
     97         /// </param>
     98         /// <returns>
     99         /// 返回截取到的字符串
    100         /// </returns>
    101         public static string GetBetween(this string str, string from, string to)
    102         {
    103             if (from == null || to == null)
    104             {
    105                 throw new ArgumentException("参数 from 与 to,都不能为 null");
    106             }
    107             int iStart, iEnd;
    108             if (from == string.Empty)
    109                 iStart = 0;
    110             else
    111                 iStart = str.IndexOf(from) + from.Length;
    112             if (to == string.Empty)
    113                 iEnd = str.Length;
    114             else
    115                 iEnd = str.IndexOf(to);
    116             return str.Substring(iStart, iEnd - iStart);
    117         }
    118 
    119         #endregion
    120 
    121         #region 2.Regex :正则操作
    122 
    123         /// <summary>
    124         /// 判断字符串是否与给定模式相匹配
    125         /// </summary>
    126         /// <param name="str">原字符串</param>
    127         /// <param name="pattern">要匹配的模式</param>
    128         /// <returns>
    129         /// 返回是否匹配
    130         /// </returns>
    131         public static bool IsMatch(this string str, string pattern)
    132         {
    133             if (str == null) return false;
    134                 
    135             return System.Text.RegularExpressions.Regex.IsMatch(str, pattern);
    136         }
    137 
    138         /// <summary>
    139         /// 查找字符串中与指定模式的所有匹配
    140         /// </summary>
    141         /// <param name="str">要匹配的字符串</param>
    142         /// <param name="pattern">进行匹配的正则表达式</param>
    143         /// <returns>
    144         /// 返回所有匹配,包括全局匹配和子匹配,匹配到的文本
    145         /// </returns>
    146         public static string[] FindAll(this string str, string pattern)
    147         {
    148             if (str == null) return null;
    149          
    150             Match m = System.Text.RegularExpressions.Regex.Match(str, pattern);
    151             return m.Groups.OfType<Group>().Select(g => g.Value).ToArray();
    152         }
    153 
    154         #endregion
    155 
    156         #region 3.Fill :填充
    157 
    158         #region 3.1.Center :居中填充
    159 
    160         /// <summary>
    161         /// 使用空格对文本进行居中填充
    162         /// </summary>
    163         /// <param name="str">被居中填充的文本</param>
    164         /// <param name="totalWidth">填充后的总字符数</param>
    165         /// <returns>
    166         /// 返回填充后的文本
    167         /// </returns>
    168         public static string Center(this string str, int totalWidth)
    169         {
    170             return Center(str, totalWidth, ' ');
    171         }
    172 
    173         /// <summary>
    174         /// 使用指定字符对文本进行居中填充
    175         /// </summary>
    176         /// <param name="str">被居中填充的文本</param>
    177         /// <param name="totalWidth">填充后的总字符数</param>
    178         /// <param name="fillWith">填充时使用的字符</param>
    179         /// <returns>
    180         /// 返回填充后的文本
    181         /// </returns>
    182         public static string Center(this string str, int totalWidth, char fillWith)
    183         {
    184             int strlen = str.Length;
    185             if (strlen >= totalWidth)
    186             {
    187                 return str;
    188             }
    189             else
    190             {
    191                 int rightLen = (totalWidth - strlen) / 2;
    192                 int leftLen = totalWidth - strlen - rightLen;
    193                 return fillWith.ToString().Repeat(leftLen) +
    194                     str + fillWith.ToString().Repeat(rightLen);
    195             }
    196         }
    197 
    198         #endregion
    199 
    200         #region 3.2.PadLeftEx :定宽左填充
    201 
    202         /// <summary>
    203         /// 按系统默认字符编码对文本进行定宽左填充(以半角字符宽度为1单位宽度)
    204         /// </summary>
    205         /// <param name="str">要填充的文本</param>
    206         /// <param name="totalByteCount">要填充到的字节长度</param>
    207         /// <returns>
    208         /// 返回填充后的文本
    209         /// </returns>
    210         public static string PadLeftEx(this string str, int totalByteCount)
    211         {
    212             return PadLeftEx(str, totalByteCount, Encoding.Default.BodyName);
    213         }
    214 
    215         /// <summary>
    216         /// 按指定字符编码对文本进行定宽左填充(以半角字符宽度为1单位宽度)
    217         /// </summary>
    218         /// <param name="str">要填充的文本</param>
    219         /// <param name="totalByteCount">要填充到的字节长度</param>
    220         /// <param name="encodingName">用于在填充过程中进行文本解析的字符编码</param>
    221         /// <returns>
    222         /// 返回填充后的文本
    223         /// </returns>
    224         public static string PadLeftEx(this string str, int totalByteCount, string encodingName)
    225         {
    226             Encoding coding = Encoding.GetEncoding(encodingName);
    227             int width = coding.GetByteCount(str);
    228             //总字节数减去原字符串多占的字节数,就是应该添加的空格数
    229             int padLen = totalByteCount - width;
    230             if (padLen <= 0)
    231                 return str;
    232             else
    233                 return str.PadLeft(padLen);
    234         }
    235 
    236         /// <summary>
    237         /// 按系统默认字符编码对文本使用指定的填充符进行定宽左填充(以半角字符宽度为1单位宽度)
    238         /// </summary>
    239         /// <param name="str">要填充的文本</param>
    240         /// <param name="totalByteCount">要填充到的字节长度</param>
    241         /// <param name="fillWith">填充符</param>
    242         /// <returns>
    243         /// 返回填充后的文本
    244         /// </returns>
    245         public static string PadLeftEx(this string str, int totalByteCount, char fillWith)
    246         {
    247             return PadLeftEx(str, totalByteCount, fillWith, Encoding.Default.BodyName);
    248         }
    249 
    250         /// <summary>
    251         /// 按指定字符编码对文本使用指定的填充符进行定宽左填充(以半角字符宽度为1单位宽度)
    252         /// </summary>
    253         /// <param name="str">要填充的文本</param>
    254         /// <param name="totalByteCount">要填充到的字节长度</param>
    255         /// <param name="fillWith">填充符</param>
    256         /// <param name="encodingName">用于在填充过程中进行文本解析的字符编码</param>
    257         /// <returns>
    258         /// 返回填充后的文本
    259         /// </returns>
    260         public static string PadLeftEx(this string str, int totalByteCount,
    261             char fillWith, string encodingName)
    262         {
    263             Encoding coding = Encoding.GetEncoding(encodingName);
    264             int fillWithWidth = coding.GetByteCount(new char[] { fillWith });
    265             int width = coding.GetByteCount(str);
    266             //总字节数减去原字符串多占的字节数,再除以填充字符的占的字节数,
    267             //就是应该添加的空格数【因为有时候是双字节的填充符,比如中文】
    268             int padLen = (totalByteCount - width) / fillWithWidth;
    269             if (padLen <= 0)
    270                 return str;
    271             else
    272                 return str.PadLeft(padLen, fillWith);
    273         }
    274 
    275         #endregion
    276 
    277         #region 3.3.CenterEx :定宽居中填充
    278 
    279         /// <summary>
    280         /// 按系统默认字符编码对文本进行定宽居中填充(以半角字符宽度为1单位宽度)
    281         /// </summary>
    282         /// <param name="str"></param>
    283         /// <param name="totalByteCount"></param>
    284         /// <returns>
    285         /// 返回填充后的文本
    286         /// </returns>
    287         public static string CenterEx(this string str, int totalByteCount)
    288         {
    289             return CenterEx(str, totalByteCount, Encoding.Default.BodyName);
    290         }
    291 
    292         /// <summary>
    293         /// 按指定的字符编码对文本进行定宽居中填充(以半角字符宽度为1单位宽度)
    294         /// </summary>
    295         /// <param name="str">要居中填充的字符串</param>
    296         /// <param name="totalByteCount">填充后的总字节数</param>
    297         /// <param name="encodingName">用于在填充过程中进行文本解析的字符编码</param>
    298         /// <returns>
    299         /// 返回填充后的文本
    300         /// </returns>
    301         public static string CenterEx(this string str, int totalByteCount, string encodingName)
    302         {
    303             Encoding coding = Encoding.GetEncoding(encodingName);
    304             int width = coding.GetByteCount(str);
    305             //总字节数减去原字符串多占的字节数,就是应该添加的空格数
    306             int padLen = totalByteCount - width;
    307             if (padLen < 0) return str;
    308             int padRight = padLen / 2;
    309             int padLeft = padLen - padRight;
    310             return " ".Repeat(padLeft) + str + " ".Repeat(padRight);
    311         }
    312 
    313         /// <summary>
    314         /// 按系统默认字符编码对文本使用指定的填充符进行定宽居中填充(以半角字符宽度为1单位宽度)
    315         /// </summary>
    316         /// <param name="str">要填充的文本</param>
    317         /// <param name="totalByteCount">填充后得到的结果包含的总字节数</param>
    318         /// <param name="fillWith">填充符</param>
    319         /// <returns>
    320         /// 返回填充后的文本
    321         /// </returns>
    322         public static string CenterEx(this string str, int totalByteCount, char fillWith)
    323         {
    324             return CenterEx(str, totalByteCount, fillWith, Encoding.Default.BodyName);
    325         }
    326 
    327         /// <summary>
    328         /// 按指定的字符编码对文本使用指定的填充符进行定宽居中填充(以半角字符宽度为1单位宽度)
    329         /// </summary>
    330         /// <param name="str">要填充的文本</param>
    331         /// <param name="totalByteCount">填充后得到的文本需达到的总字节数</param>
    332         /// <param name="fillWith">填充符</param>
    333         /// <param name="encodingName">用于在填充过程中进行文本解析的字符编码</param>
    334         /// <returns>
    335         /// 返回填充后的文本
    336         /// </returns>
    337         public static string CenterEx(this string str, int totalByteCount,
    338             char fillWith, string encodingName)
    339         {
    340             Encoding coding = Encoding.GetEncoding(encodingName);
    341             int fillWithWidth = coding.GetByteCount(new char[] { fillWith });
    342             string fillStr = fillWith.ToString();
    343             int width = coding.GetByteCount(str);
    344             //总字节数减去原字符串多占的字节数,就是应该添加的空格数
    345             int padLen = (totalByteCount - width) / fillWithWidth;
    346             if (padLen < 0) return str;
    347             int padRight = padLen / 2;
    348             int padLeft = padLen - padRight;
    349             return fillStr.Repeat(padLeft) + str + fillStr.Repeat(padRight);
    350         }
    351 
    352         #endregion
    353 
    354         #region 3.4.PadRight : 定宽右填充
    355 
    356         /// <summary>
    357         /// 按系统默认字符编码对文本进行定宽右填充(以半角字符宽度为1单位宽度)
    358         /// </summary>
    359         /// <param name="str">要填充的文本</param>
    360         /// <param name="totalByteCount">要填充到的字节长度</param>
    361         /// <returns>
    362         /// 返回填充后的文本
    363         /// </returns>
    364         public static string PadRightEx(this string str, int totalByteCount)
    365         {
    366             return PadRightEx(str, totalByteCount, Encoding.Default.BodyName);
    367         }
    368 
    369         /// <summary>
    370         /// 按指定字符编码对文本进行定宽右填充(以半角字符宽度为1单位宽度)
    371         /// </summary>
    372         /// <param name="str">要填充的文本</param>
    373         /// <param name="totalByteCount">要填充到的字节长度</param>
    374         /// <param name="encodingName">用于在填充过程中进行文本解析的字符编码</param>
    375         /// <returns>
    376         /// 返回填充后的文本
    377         /// </returns>
    378         public static string PadRightEx(this string str, int totalByteCount, string encodingName)
    379         {
    380             Encoding coding = Encoding.GetEncoding(encodingName);
    381             int width = coding.GetByteCount(str);
    382             //总字节数减去原字符串多占的字节数,就是应该添加的空格数
    383             int padLen = totalByteCount - width;
    384             if (padLen <= 0)
    385                 return str;
    386             else
    387                 return str.PadRight(padLen);
    388         }
    389 
    390         /// <summary>
    391         /// 按系统默认字符编码对文本使用指定的填充符进行定宽右填充(以半角字符宽度为1单位宽度)
    392         /// </summary>
    393         /// <param name="str">要填充的文本</param>
    394         /// <param name="totalByteCount">要填充到的字节长度</param>
    395         /// <param name="fillWith">填充符</param>
    396         /// <returns>
    397         /// 返回填充后的文本
    398         /// </returns>
    399         public static string PadRightEx(this string str, int totalByteCount, char fillWith)
    400         {
    401             return PadRightEx(str, totalByteCount, fillWith, Encoding.Default.BodyName);
    402         }
    403 
    404         /// <summary>
    405         /// 按指定字符编码对文本使用指定的填充符进行定宽右填充(以半角字符宽度为1单位宽度)
    406         /// </summary>
    407         /// <param name="str">要填充的文本</param>
    408         /// <param name="totalByteCount">要填充到的字节长度</param>
    409         /// <param name="fillWith">填充符</param>
    410         /// <param name="encodingName">用于在填充过程中进行文本解析的字符编码</param>
    411         /// <returns>
    412         /// 返回填充后的文本
    413         /// </returns>
    414         public static string PadRightEx(this string str, int totalByteCount,
    415             char fillWith, string encodingName)
    416         {
    417             Encoding coding = Encoding.GetEncoding(encodingName);
    418             int fillWithWidth = coding.GetByteCount(new char[] { fillWith });
    419             int width = coding.GetByteCount(str);
    420             //总字节数减去原字符串多占的字节数,再除以填充字符的占的字节数,
    421             //就是应该添加的空格数【因为有时候是双字节的填充符,比如中文】
    422             int padLen = (totalByteCount - width) / fillWithWidth;
    423             if (padLen <= 0)
    424                 return str;
    425             else
    426                 return str.PadRight(padLen, fillWith);
    427         }
    428 
    429         #endregion
    430 
    431         #endregion
    432 
    433         #region 4.Repeat :复制字符串
    434 
    435         /// <summary>
    436         /// 取得字符串的指定次重复后的字符串
    437         /// </summary>
    438         /// <param name="str">原字符串</param>
    439         /// <param name="times">要重复的次数</param>
    440         /// <returns>
    441         /// 返回复制了指定次的字符串
    442         /// </returns>
    443         public static string Repeat(this string str, int times)
    444         {
    445             if (times < 0)
    446                 throw new ArgumentException("参数 times 不能小于0.");
    447 
    448             if (str == null)
    449                 throw new ArgumentException("要复制的字符串不能为 null.");
    450 
    451             if (str == string.Empty) return string.Empty;
    452 
    453             StringBuilder sb = new StringBuilder();
    454             for (int i = 1; i <= times; i++)
    455             {
    456                 sb.Append(str);
    457             }
    458             return sb.ToString();
    459         }
    460 
    461         /// <summary>
    462         /// 取得字符串的指定次重复后的字符串
    463         /// </summary>
    464         /// <param name="str">原字符串</param>
    465         /// <param name="totalByteCount">要重复到的字符宽度</param>
    466         /// <returns>
    467         /// 返回复制了指定次的字符串
    468         /// </returns>
    469         public static string RepeatEx(this string str, int totalByteCount)
    470         {
    471             return StringEx.RepeatEx(str, totalByteCount, Encoding.Default.BodyName);
    472         }
    473 
    474         /// <summary>
    475         /// 取得字符串的指定次重复后的字符串
    476         /// </summary>
    477         /// <param name="str">原字符串</param>
    478         /// <param name="totalByteCount">要重复到的字符宽度</param>
    479         /// <param name="encodingName">用于在复制过程中进行文本解析的字符编码</param>
    480         /// <returns>
    481         /// 返回复制了指定次的字符串
    482         /// </returns>
    483         public static string RepeatEx(this string str, int totalByteCount, string encodingName)
    484         {
    485             if (totalByteCount < 0)
    486                 throw new ArgumentException("参数 times 不能小于0.");
    487 
    488             if (str == null)
    489                 throw new ArgumentException("要复制的字符串不能为 null.");
    490 
    491             if (str == string.Empty) return string.Empty;
    492 
    493             Encoding coding = Encoding.GetEncoding(encodingName);
    494             int len = coding.GetByteCount(str);
    495             int times = totalByteCount / len;
    496             StringBuilder sb = new StringBuilder();
    497             for (int i = 1; i <= times; i++)
    498             {
    499                 sb.Append(str);
    500             }
    501             return sb.ToString();
    502         }
    503 
    504         #endregion
    505 
    506         #region 5.Parser :从字符串或表式文本提取对象
    507 
    508         #region Parsers : Common Parsers and Parsers Maker
    509 
    510         public delegate bool TryParse<T>(string valueStr, out T value);
    511 
    512         public static readonly Dictionary<Type, object> Parsers =
    513             new Dictionary<Type, object>();
    514 
    515         /// <summary>
    516         /// <see cref="char"/> 类型字符串解析器
    517         /// </summary>
    518         public static TryParse<char> CharParser = 
    519             (string valueStr, out char value) => Char.TryParse(valueStr, out value);
    520 
    521         /// <summary>
    522         /// <see cref="bool"/> 类型字符串解析器
    523         /// </summary>
    524         public static TryParse<bool> BooleanParser = 
    525             (string valueStr, out bool value) => Boolean.TryParse(valueStr, out value);
    526 
    527         /// <summary>
    528         /// <see cref="byte"/> 类型字符串解析器
    529         /// </summary>
    530         public static TryParse<byte> ByteParser = 
    531             (string valueStr, out byte value) => Byte.TryParse(valueStr, out value);
    532 
    533         /// <summary>
    534         /// <see cref="sbyte"/> 类型字符串解析器
    535         /// </summary>
    536         public static TryParse<sbyte> SByteParser = 
    537             (string valueStr, out sbyte value) => SByte.TryParse(valueStr, out value);
    538 
    539         /// <summary>
    540         /// <see cref="short"/> 类型字符串解析器
    541         /// </summary>
    542         public static TryParse<short> Int16Parser =
    543             (string valueStr, out short value) => Int16.TryParse(valueStr, out value);
    544 
    545         /// <summary>
    546         /// <see cref="int"/> 类型字符串解析器
    547         /// </summary>
    548         public static TryParse<int> Int32Parser = 
    549             (string valueStr, out int value) => Int32.TryParse(valueStr, out value);
    550 
    551         /// <summary>
    552         /// <see cref="long"/> 类型字符串解析器
    553         /// </summary>
    554         public static TryParse<long> Int64Parser = 
    555             (string valueStr, out long value) => Int64.TryParse(valueStr, out value);
    556 
    557         /// <summary>
    558         /// <see cref="ushort"/> 类型字符串解析器
    559         /// </summary>
    560         public static TryParse<ushort> UInt16Parser =
    561             (string valueStr, out ushort value) => UInt16.TryParse(valueStr, out value);
    562 
    563         /// <summary>
    564         /// <see cref="uint"/> 类型字符串解析器
    565         /// </summary>
    566         public static TryParse<uint> UInt32Parser = 
    567             (string valueStr, out uint value) => UInt32.TryParse(valueStr, out value);
    568 
    569         /// <summary>
    570         /// <see cref="ulong"/> 类型字符串解析器
    571         /// </summary>
    572         public static TryParse<ulong> UInt64Parser = 
    573             (string valueStr, out ulong value) => UInt64.TryParse(valueStr, out value);
    574 
    575         /// <summary>
    576         /// <see cref="float"/> 类型字符串解析器
    577         /// </summary>
    578         public static TryParse<float> SingleParser =
    579             (string valueStr, out float value) => Single.TryParse(valueStr, out value);
    580 
    581         /// <summary>
    582         /// <see cref="double"/> 类型字符串解析器
    583         /// </summary>
    584         public static TryParse<double> DoubleParser = 
    585             (string valueStr, out double value) => Double.TryParse(valueStr, out value);
    586 
    587         /// <summary>
    588         /// <see cref="decimal"/> 类型字符串解析器
    589         /// </summary>
    590         public static TryParse<decimal> DecimalParser = 
    591             (string valueStr, out decimal value) => Decimal.TryParse(valueStr, out value);
    592 
    593         /// <summary>
    594         /// <see cref="DateTime"/> 类型字符串解析器
    595         /// </summary>
    596         public static TryParse<DateTime> DateTimeParser =
    597             (string valueStr, out DateTime value) => DateTime.TryParse(valueStr, out value);
    598 
    599         /// <summary>
    600         /// <see cref="TimeSpan"/> 类型字符串解析器
    601         /// </summary>
    602         public static TryParse<TimeSpan> TimeSpanParser =
    603             (string valueStr, out TimeSpan value) => TimeSpan.TryParse(valueStr, out value);
    604 
    605         /// <summary>
    606         /// 获取指定枚举类型的字符串解析器
    607         /// </summary>
    608         /// <typeparam name="TEnum">给定枚举类型</typeparam>
    609         /// <exception cref="ArgumentException">
    610         /// 要求 <typeparamref name="TEnum"/> 是一个具体的枚举类型
    611         /// </exception>
    612         /// <remarks>
    613         /// <para>这里之所以不用约束条件限制死,是为了内部方法如 </para>
    614         /// <para><see cref="StringEx.VParse{TValue}(string, TryParse{TValue}, bool)"/></para>
    615         /// <see cref="StringEx.VParseTable{TValue}(string, bool, TryParse{TValue}, bool)"/>
    616         /// 调用的方便
    617         /// </remarks>
    618         /// <returns>
    619         /// 如果指定的类型参数确实是一个枚举类型,就返回它的字符串解析器;否则,报错
    620         /// </returns>
    621         public static TryParse<TEnum> GetEnumParser<TEnum>()
    622             where TEnum : struct
    623         {
    624             if (typeof(TEnum).IsEnum)
    625                 return (string valueStr, out TEnum value) =>
    626                     Enum.TryParse(valueStr, out value);
    627             else
    628                 throw new ArgumentException("必须是枚举类型", nameof(TEnum));
    629         }
    630 
    631         /// <summary>
    632         /// 重置解析器容器
    633         /// </summary>
    634         /// <param name="onlyCommonParser">仅重置常用的类型解析器</param>
    635         public static void ResetParsers(bool onlyCommonParser)
    636         {
    637             if (!onlyCommonParser) StringEx.Parsers.Clear();
    638             StringEx.Parsers[typeof(char)] = StringEx.CharParser;
    639             StringEx.Parsers[typeof(bool)] = StringEx.BooleanParser;
    640             StringEx.Parsers[typeof(byte)] = StringEx.ByteParser;
    641             StringEx.Parsers[typeof(sbyte)] = StringEx.SByteParser;
    642             StringEx.Parsers[typeof(short)] = StringEx.Int16Parser;
    643             StringEx.Parsers[typeof(int)] = StringEx.Int32Parser;
    644             StringEx.Parsers[typeof(long)] = StringEx.Int64Parser;
    645             StringEx.Parsers[typeof(ushort)] = StringEx.UInt16Parser;
    646             StringEx.Parsers[typeof(uint)] = StringEx.UInt32Parser;
    647             StringEx.Parsers[typeof(ulong)] = StringEx.UInt64Parser;
    648             StringEx.Parsers[typeof(float)] = StringEx.SingleParser;
    649             StringEx.Parsers[typeof(double)] = StringEx.DoubleParser;
    650             StringEx.Parsers[typeof(decimal)] = StringEx.DecimalParser;
    651             StringEx.Parsers[typeof(DateTime)] = StringEx.DateTimeParser;
    652             StringEx.Parsers[typeof(TimeSpan)] = StringEx.TimeSpanParser;
    653         }
    654 
    655         /// <summary>
    656         /// 通过反射获取指定类型的 bool TryParse(string s, out T value) 静态方法
    657         /// </summary>
    658         /// <typeparam name="T">要获取方法的类型</typeparam>
    659         /// <returns>
    660         /// 如果找到这个方法,就返回它;找不到,就报错
    661         /// </returns>
    662         private static TryParse<T> GetParser<T>()
    663         {
    664             Type t = typeof(T);
    665 
    666             MethodInfo miTryParse = t.GetMethod("TryParse", BindingFlags.Public |
    667                 BindingFlags.Static, null, CallingConventions.Any,
    668                 new Type[] { typeof(string), typeof(T).MakeByRefType() }, null);
    669             if (miTryParse == null)
    670                 throw new Exception("类型[" + t.FullName +
    671                     "]没有[bool TryParse(string s, out " + t.Name + 
    672                     " value)]静态方法,无法完成解析");
    673 
    674             return Delegate.CreateDelegate(typeof(TryParse<T>), miTryParse)
    675                 as TryParse<T>;
    676         }
    677 
    678         #endregion
    679 
    680         /// <summary>
    681         /// 将字符串,使用指定的解析器方法(如果有提供),解析成可空的目标类型对象
    682         /// </summary>
    683         /// <typeparam name="TValue">要解析成的目标类型的可空类型所包装的类型</typeparam>
    684         /// <param name="valueStr">要解析的字符串</param>
    685         /// <param name="parser">
    686         /// 字符串解析器方法
    687         /// <para>当某类型的解析器被传入调用一次,该解析器会被缓存;</para>
    688         /// <para>解析器是与解析的目标类型绑定的,下次再调用,不需要再传此参数;</para>
    689         /// <para>如果再次传入,会视情况(是否相等)覆盖上次调用时所用的解析器</para>
    690         /// <para>当您未指定解析器方法时,将尝试取得目标类型的固有解析器,如果没找到,将会报错</para>
    691         /// <para>手传解析器,比目标类型原生解析器具有更高的优先级</para>
    692         /// <para>本扩展方法类 StringEx,在加载之初,已经初始化了如下常用类型的字符串解析器:</para>
    693         /// <para>char/bool/byte/sbyte/short/int/long/ushort/uint/ulong/float/double/decimal/DateTime/TimeSpan</para>
    694         /// <para>另外对于枚举类型,也会自动生成 <typeparamref name="TValue"/> 类型的解析器 Enum.TryParse </para>
    695         /// </param>
    696         /// <param name="temp">解析器是否是临时解析器,如果是,则不会被保存</param>
    697         /// <returns>
    698         /// 解析成功,返回解析出来的值类型对象;失败,则返回 null
    699         /// </returns>
    700         /// <remarks>
    701         /// <para>如果提供了解析器,本方法通过给定的解析器,解析给定的字符器到目标类型</para>
    702         /// <para>否则,本方法尝试通过目标类型的 bool TryParse(string s, out TRefer value) 静态方法来实现功能</para>
    703         /// <para>如果指定的目标类型,不包含此种签名的静态方法,则会报错</para>
    704         /// </remarks>
    705         public static TValue? VParse<TValue>(this string valueStr, 
    706             TryParse<TValue> parser = null, bool temp = false)
    707             where TValue : struct
    708         {
    709             Type t = typeof(TValue);
    710 
    711             object proc;
    712             if (parser == null)
    713             {
    714                 if (StringEx.Parsers.ContainsKey(t))
    715                     proc = StringEx.Parsers[t];
    716                 else
    717                 {
    718                     if (t.IsEnum)
    719                         proc = StringEx.GetEnumParser<TValue>();
    720                     else
    721                         proc = StringEx.GetParser<TValue>();
    722                 }
    723             }
    724             else
    725                 proc = parser;
    726 
    727             if (!temp &&
    728                 (!StringEx.Parsers.ContainsKey(t) ||
    729                 StringEx.Parsers[t] != proc))
    730                 StringEx.Parsers.Add(t, proc);
    731 
    732             TryParse<TValue> tryParse = proc as TryParse<TValue>;
    733             if (tryParse(valueStr, out TValue value))
    734                 return value;
    735             else
    736                 return null;
    737         }
    738 
    739         /// <summary>
    740         /// 将字符串,使用指定的解析器方法(如果有提供),解析成目标类型对象
    741         /// </summary>
    742         /// <typeparam name="TRefer">要解析成的目标类型</typeparam>
    743         /// <param name="valueStr">要解析的字符串</param>
    744         /// <param name="parser">
    745         /// 字符串解析器方法
    746         /// <para>当某类型的解析器被传入调用一次,该解析器会被缓存;</para>
    747         /// <para>解析器是与解析的目标类型绑定的,下次再调用,不需要再传此参数;</para>
    748         /// <para>如果再次传入,会视情况(是否相等)覆盖上次调用时所用的解析器</para>
    749         /// <para>当您未指定解析器方法时,将尝试取得目标类型的固有解析器,如果没找到,将会报错</para>
    750         /// <para>手传解析器,比目标类型原生解析器具有更高的优先级</para>
    751         /// <para>本扩展方法类 StringEx,在加载之初,已经初始化了如下常用类型的字符串解析器:</para>
    752         /// <para>char/bool/byte/sbyte/short/int/long/ushort/uint/ulong/float/double/decimal/DateTime/TimeSpan</para>
    753         /// </param>
    754         /// <param name="temp">解析器是否是临时解析器,如果是,则不会被保存</param>
    755         /// <returns>
    756         /// 解析成功,则返回解析到的对象;失败,则返回 null
    757         /// </returns>
    758         /// <remarks>
    759         /// <para>如果提供了解析器,本方法通过给定的解析器,解析给定的字符器到目标类型</para>
    760         /// <para>否则,本方法尝试通过目标类型的 bool TryParse(string s, out TRefer value) 静态方法来实现功能</para>
    761         /// <para>如果指定的目标类型,不包含此种签名的静态方法,则会报错</para>
    762         /// </remarks>
    763         public static TRefer RParse<TRefer>(this string valueStr, 
    764             TryParse<TRefer> parser = null, bool temp = false)
    765             where TRefer : class
    766         {
    767             Type t = typeof(TRefer);
    768 
    769             object proc;
    770             if (parser == null)
    771             {
    772                 if (StringEx.Parsers.ContainsKey(t))
    773                     proc = StringEx.Parsers[t];
    774                 else
    775                     proc = StringEx.GetParser<TRefer>();
    776             }
    777             else
    778             {
    779                 proc = parser;
    780             }
    781 
    782             if (!temp &&
    783                 (!StringEx.Parsers.ContainsKey(t) ||
    784                 StringEx.Parsers[t] != proc))
    785                 StringEx.Parsers.Add(t, proc);
    786 
    787             TryParse<TRefer> tryParse = proc as TryParse<TRefer>;
    788             tryParse(valueStr, out TRefer value);
    789             return value;
    790         }
    791 
    792         /// <summary>
    793         /// 将表式文本,使用指定的解析器方法(如果有提供),解析成可空的目标类型对象数组
    794         /// </summary>
    795         /// <typeparam name="TValue">要解析成的目标类型</typeparam>
    796         /// <param name="tableText">要解析的表式文本</param>
    797         /// <param name="noWhiteLines">是否抛弃空白行</param>
    798         /// <param name="parser">
    799         /// 表式文本解析器方法
    800         /// <para>当某类型的解析器被传入调用一次,该解析器会被缓存,除非指定它是临时的;</para>
    801         /// <para>解析器是与解析的目标类型绑定的,下次再调用,不需要再传此参数;</para>
    802         /// <para>如果再次传入,会视情况(是否相等)覆盖上次调用时所用的解析器</para>
    803         /// <para>当您未指定解析器方法时,将尝试取得目标类型的固有解析器,如果没找到,将会报错</para>
    804         /// <para>手传解析器,比目标类型原生解析器具有更高的优先级</para>
    805         /// <para>本扩展方法类 StringEx,在加载之初,已经初始化了如下常用类型的字符串解析器:</para>
    806         /// <para>char/bool/byte/sbyte/short/int/long/ushort/uint/ulong/float/double/decimal/DateTime/TimeSpan</para>
    807         /// <para>另外对于枚举类型,也会自动生成 <typeparamref name="TValue"/> 类型的解析器 Enum.TryParse </para>
    808         /// </param>
    809         /// <param name="temp">解析器是否是临时解析器,如果是,则不会被保存</param>
    810         /// <returns>
    811         /// 解析成功,则返回解析到的对象;失败,则返回 null
    812         /// </returns>
    813         /// <remarks>
    814         /// <para>如果提供了解析器,本方法通过给定的解析器,解析给定的表式文本到目标类型</para>
    815         /// <para>否则,本方法尝试通过目标类型的 bool TryParse(string s, out TRefer value) 静态方法来实现功能</para>
    816         /// <para>如果指定的目标类型,不包含此种签名的静态方法,则会报错</para>
    817         /// </remarks>
    818         public static TValue?[] VParseTable<TValue>(
    819             this string tableText, bool noWhiteLines = true,
    820             TryParse<TValue> parser = null, bool temp = false)
    821             where TValue : struct
    822         {
    823             Type t = typeof(TValue);
    824 
    825             object proc;
    826             if (parser == null)
    827             {
    828                 if (StringEx.Parsers.ContainsKey(t))
    829                     proc = StringEx.Parsers[t];
    830                 else
    831                 {
    832                     if (t.IsEnum)
    833                         proc = StringEx.GetEnumParser<TValue>();
    834                     else
    835                         proc = StringEx.GetParser<TValue>();
    836                 }
    837             }
    838             else
    839                 proc = parser;
    840 
    841             if (!temp &&
    842                 (!StringEx.Parsers.ContainsKey(t) ||
    843                 StringEx.Parsers[t] != proc))
    844                 StringEx.Parsers.Add(t, proc);
    845 
    846             TryParse<TValue> tryParse = proc as TryParse<TValue>;
    847             List<TValue?> values = new List<TValue?>();
    848             foreach(string line in tableText.GetLines(noWhiteLines))
    849             {
    850                 if (tryParse(line, out TValue value))
    851                     values.Add(value);
    852                 else
    853                     values.Add(null);
    854             }
    855 
    856             return values.ToArray();
    857         }
    858 
    859         /// <summary>
    860         /// 将表式文本,使用指定的解析器方法(如果有提供),解析成目标类型对象数组
    861         /// </summary>
    862         /// <typeparam name="TRefer">要解析成的目标类型</typeparam>
    863         /// <param name="tableText">要解析的表式文本</param>
    864         /// <param name="noWhiteLines">是否抛弃空白行</param>
    865         /// <param name="parser">
    866         /// 表式文本解析器方法
    867         /// <para>当某类型的解析器被传入调用一次,该解析器会被缓存,除非指定它是临时的;</para>
    868         /// <para>解析器是与解析的目标类型绑定的,下次再调用,不需要再传此参数;</para>
    869         /// <para>如果再次传入,会视情况(是否相等)覆盖上次调用时所用的解析器</para>
    870         /// <para>当您未指定解析器方法时,将尝试取得目标类型的固有解析器,如果没找到,将会报错</para>
    871         /// <para>手传解析器,比目标类型原生解析器具有更高的优先级</para>
    872         /// <para>本扩展方法类 <see cref="StringEx"/>,在加载之初,已经初始化了如下常用类型的字符串解析器:</para>
    873         /// <para>char/bool/byte/sbyte/short/int/long/ushort/uint/ulong/float/double/decimal/DateTime/TimeSpan</para>
    874         /// </param>
    875         /// <param name="temp">解析器是否是临时解析器,如果是,则不会被保存</param>
    876         /// <returns>
    877         /// 解析成功,则返回解析到的对象;失败,则返回 null
    878         /// </returns>
    879         /// <remarks>
    880         /// <para>如果提供了解析器,本方法通过给定的解析器,解析给定的表式文本到目标类型</para>
    881         /// <para>否则,本方法尝试通过目标类型的 bool TryParse(string s, out TRefer value) 静态方法来实现功能</para>
    882         /// <para>如果指定的目标类型,不包含此种签名的静态方法,则会报错</para>
    883         /// </remarks>
    884         public static TRefer[] RParseTable<TRefer>(
    885             this string tableText, bool noWhiteLines = true,
    886             TryParse<TRefer> parser = null, bool temp = false)
    887             where TRefer : class
    888         {
    889             Type t = typeof(TRefer);
    890 
    891             object proc;
    892             if (parser == null)
    893             {
    894                 if (StringEx.Parsers.ContainsKey(t))
    895                     proc = StringEx.Parsers[t];
    896                 else
    897                     proc = StringEx.GetParser<TRefer>();
    898             }
    899             else
    900             {
    901                 proc = parser;
    902             }
    903 
    904             if (!temp &&
    905                 (!StringEx.Parsers.ContainsKey(t) ||
    906                 StringEx.Parsers[t] != proc))
    907                 StringEx.Parsers.Add(t, proc);
    908 
    909             TryParse<TRefer> tryParse = proc as TryParse<TRefer>;
    910 
    911             return tableText.GetLines(noWhiteLines)
    912                 .Select(line =>
    913                 {
    914                     tryParse(line, out TRefer value);
    915                     return value;
    916                 }).ToArray();
    917         }
    918      
    919         #endregion
    920 
    921         #region Z.Unclassified :未分类
    922 
    923         /// <summary>
    924         /// 获取指定字符器的字节宽度
    925         /// </summary>
    926         /// <param name="str"></param>
    927         /// <returns></returns>
    928         public static int GetWidth(this string str)
    929         {
    930             Encoding coding = Encoding.Default;
    931             return coding.GetByteCount(str);
    932         }
    933 
    934         /// <summary>
    935         /// 使用指定格式化器格式化值表
    936         /// </summary>
    937         /// <param name="format">格式化器</param>
    938         /// <param name="values">值表</param>
    939         /// <returns>
    940         /// 返回格式化后的字符串
    941         /// </returns>
    942         public static string FormatWith(this string format, params object[] values)
    943         {
    944             return string.Format(format, values);
    945         }
    946 
    947         /// <summary>
    948         /// 从指定字符器获取行
    949         /// </summary>
    950         /// <param name="text">指定的字符器</param>
    951         /// <param name="noWhiteLines">是否抛弃空白行</param>
    952         /// <returns></returns>
    953         public static string[] GetLines(this string text, bool noWhiteLines = false)
    954         {
    955             if(noWhiteLines)
    956                 return text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None)
    957                     .Where(line => !string.IsNullOrWhiteSpace(line)).ToArray();
    958             else
    959                 return text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
    960         }
    961 
    962         #endregion
    963 
    964     }
    965 }

    以下是试验代码:

      1         internal class WeekDay
      2         {
      3             public int Index { get; set; }
      4 
      5             public string Name { get; set; }
      6 
      7             public string ShortName { get; set; }
      8 
      9             public WeekDay(int index, string name, string shortName)
     10             {
     11                 this.Index = index;
     12                 this.Name = name;
     13                 this.ShortName = shortName;
     14             }
     15 
     16             public override string ToString()
     17             {
     18                 return $"[{ this.Index }, { this.ShortName }, { this.Name }]";
     19             }
     20         }
     21 
     22         private static void StringEx_Parse()
     23         {
     24             Console.WriteLine("值类型字符串解析器".CenterEx(80, '='));
     25             ///使用值类型字符串解析方法解析枚举字符串
     26             Console.WriteLine("使用值类型字符串解析方法解析枚举字符串".CenterEx(80, '-'));
     27             Console.WriteLine(DayOfWeek.Sunday.ToString().VParse<DayOfWeek>().Value);
     28             Console.WriteLine("使用值类型字符串解析方法解析当前时间字符串".CenterEx(80, '-'));
     29             Console.WriteLine(DateTime.Now.ToString().VParse<DateTime>().Value);
     30             string doubleStr = "1.35923";
     31             ///给定临时解析器,调用值类型字符串解析方法解析双精度浮点型字符串
     32             Console.WriteLine("带临时解析器,使用值类型字符串解析方法解析双精度浮点型字符串".CenterEx(80, '-'));
     33             Console.WriteLine(doubleStr.VParse<double>(
     34                 (string s, out double d) =>
     35                 {
     36                     bool okey = double.TryParse(s, out d);
     37                     d = (double)Math.Round(d, 2);
     38                     return okey;
     39                 }, true));
     40             ///不带解析器,调用值类型字符串解析方法解析双精度浮点型字符串
     41             Console.WriteLine("不带解析器,调用值类型字符串解析方法解析双精度浮点型字符串".CenterEx(80, '-'));
     42             Console.WriteLine("1.35923".VParse<double>());
     43             Console.WriteLine("1.32e-5".VParse<double>());
     44             ///调用引用类型字符串解析方法解析引用类型字符串
     45             Console.WriteLine("调用引用类型字符串解析方法解析引用类型字符串".CenterEx(80, '='));
     46             Console.WriteLine("调用引用类型字符串解析方法解析 Version 类型字符串".CenterEx(80, '-'));
     47             Console.WriteLine("1.2.3.4".RParse<Version>());
     48             Console.WriteLine("调用引用类型字符串解析方法解析 IPAddress 类型字符串".CenterEx(80, '='));
     49             Console.WriteLine("127.0.0.1".RParse<System.Net.IPAddress>().AddressFamily);
     50             ///给定解析器,调用引用类型字符串解析方法解析引用类型字符串
     51             Console.WriteLine("调用引用类型字符串解析方法解析 int[] 类型字符串".CenterEx(80, '='));
     52             var x = "1,2,3".RParse<int[]>((string s, out int[] value) =>
     53             {
     54                 string[] values = s.Split(',');
     55                 value = values.Select(v => int.Parse(v)).ToArray();
     56                 return true;
     57             });
     58             Console.WriteLine(x.JoinToText(", ", "[", "]"));
     59 
     60             ///表式文本解析器
     61             var days = Enum.GetValues(typeof(DayOfWeek)).OfType<DayOfWeek>()
     62                 .Select(d => ((int)d, d.ToString(), d.ToString().Substring(0, 3)))
     63                 .Cast<(int Index, string Name, string ShortName)>()
     64                 .ToArray();
     65             string tableText = days.JoinToText("
    ");
     66 
     67             Console.WriteLine("表式文本解析".CenterEx(80, '='));
     68             Console.WriteLine(tableText);
     69             ///值类型表式文本解析器
     70             var tupleParser = new StringEx.TryParse<(int Number, string Name, string ShortName)>(
     71                 (string s, out (int Number, string Name, string ShortName) value) =>
     72             {
     73                 bool okey = s != null && s.Length > 2 &&
     74                     s.StartsWith("(") && s.EndsWith(")");
     75                 if (!okey)
     76                 {
     77                     value = default;
     78                     return false;
     79                 }
     80 
     81                 string[] strs = s.Substring(1, s.Length - 2).Split(',');
     82                 okey = okey && strs.Length == 3;
     83                 if (!okey)
     84                 {
     85                     value = default;
     86                     return false;
     87                 }
     88 
     89                 value = (int.Parse(strs[0].Trim()), strs[1].Trim(), strs[2].Trim());
     90                 return okey;
     91             });
     92             Console.WriteLine("表式文本向 tuple[] 解析".CenterEx(80, '='));
     93             var tuples = tableText.VParseTable(parser: tupleParser);
     94             Console.WriteLine(tuples.JoinToText("
    "));
     95             ///引用类型表式文本解析器
     96             var weekDaysParser = new StringEx.TryParse<WeekDay>(
     97                 (string s, out WeekDay value) =>
     98             {
     99                 bool okey = s != null && s.Length > 2 && 
    100                     s.StartsWith("(") && s.EndsWith(")");
    101                 if (!okey)
    102                 {
    103                     value = default;
    104                     return false;
    105                 }
    106 
    107                 string[] strs = s.Substring(1, s.Length - 2).Split(',');
    108                 okey = okey && strs.Length == 3;
    109                 if (!okey)
    110                 {
    111                     value = default;
    112                     return false;
    113                 }
    114 
    115                 value = new WeekDay(
    116                     int.Parse(strs[0].Trim()), strs[1].Trim(), strs[2].Trim());
    117                 return okey;
    118             });
    119             Console.WriteLine("表式文本向 WeekDay[] 解析".CenterEx(80, '='));
    120             var weekDays = tableText.RParseTable(parser: weekDaysParser);
    121             Console.WriteLine(weekDays.JoinToText("
    "));
    122             ///含错误行的表式文本
    123             Console.WriteLine("有错误的表式文本解析".CenterEx(80, '='));
    124             tableText = tableText.Replace("(2", "<78").Replace("5, ", "##");
    125             Console.WriteLine(tableText);
    126             Console.WriteLine("有错误的表式文本向 tuple[] 解析".CenterEx(80, '-'));
    127             tuples = tableText.VParseTable(parser: tupleParser);
    128             Console.WriteLine(tuples.JoinToText("
    "));
    129             Console.WriteLine("有错误的表式文本向 WeekDay[] 解析".CenterEx(80, '-'));
    130             weekDays = tableText.RParseTable(parser: weekDaysParser);
    131             Console.WriteLine(weekDays.JoinToText("
    "));
    132         }
  • 相关阅读:
    httpClient 中的post或者get请求
    java自带的http get/post请求servlet
    java文件的读写操作
    java文件创建和删除
    java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'waterQuality
    win10系统jdk安装和环境变量配置
    echarts报错Can't get dom width or height
    org.springframework.beans.factory.BeanCreationException
    jsp与后台交换数据(安全目录外)
    LeetCode —— Invert Binary Tree
  • 原文地址:https://www.cnblogs.com/nutix/p/13586110.html
Copyright © 2011-2022 走看看