【问题标题】:Add separator to string at every N characters?在每 N 个字符处向字符串添加分隔符?
【发布时间】:2012-03-29 19:25:53
【问题描述】:

我有一个包含二进制数字的字符串。如何在每个 8 位后分隔字符串?

假设字符串是:

string x = "111111110000000011111111000000001111111100000000";

我想在每 8 个字符后添加一个分隔符,例如 ,(逗号)。

输出应该是:

"11111111,00000000,11111111,00000000,11111111,00000000,"

然后我想将它发送到一个列表最后 8 个字符的第一个,然后是前 8 个字符(除了 ,)等等。

我该怎么做?

【问题讨论】:

标签: c# string grouping string-formatting


【解决方案1】:
Regex.Replace(myString, ".{8}", "$0,");

如果你想要一个由八个字符组成的字符串数组,那么下面的方法可能更简单:

Regex.Split(myString, "(?<=^(.{8})+)");

只会在字符串前面有八个字符的倍数处拆分字符串。

【讨论】:

  • 可能值得断言它们只是二进制“数字”,而不是任何字符:"[01]{8}"
  • 好吧,我希望他们知道他们投入了什么样的数据:)
  • 替换部分中的$0指的是整个匹配($1是第一个捕获组等)。你也可以使用$&amp;
  • 虽然请求确实要求尾随逗号,但如果开发人员不想要尾随逗号,他们可以将 RegEx 模式更改为“.{8}(?! $)" 使用负前瞻来确保它与字符串末尾的八个字符不匹配。
  • 如果你不想要最后一个逗号,你可以使用这个正则表达式.{8}(?!$)
【解决方案2】:

试试这个:

var s = "111111110000000011111111000000001111111100000000";
var list = Enumerable
    .Range(0, s.Length/8)
    .Select(i => s.Substring(i*8, 8));
var res = string.Join(",", list);

【讨论】:

  • 是的确实...谢谢@dasbinkeblight
  • 顺便说一句,您不需要ToList(),因为string.Joinan overload that takes an IEnumerable(从.NET 4 开始)。
  • @Joey 我知道,但我最初误解了这个问题。我阅读了 OP 说“然后我想将它发送到列表”的部分,并用ToList() 发布了一个答案,没有string.Join 行。然后我重新阅读问题,添加res = ...,并保存,但我忘记删除ToList()
  • 在制作扩展方法后遇到了一个问题。如果字符串比间隔短。 if (s.Length
  • 这个方法截取字符串的长度。如果s 字符串包含另外 7 个字符,则不会返回这些字符。
【解决方案3】:

...或者老派:

public static List<string> splitter(string in, out string csv)
{
     if (in.length % 8 != 0) throw new ArgumentException("in");
     var lst = new List<string>(in/8);

     for (int i=0; i < in.length / 8; i++) lst.Add(in.Substring(i*8,8));

     csv = string.Join(",", lst); //This we want in input order (I believe)
     lst.Reverse(); //As we want list in reverse order (I believe)

     return lst;
}

【讨论】:

  • 我称之为易于阅读 - 但对每个人来说都是自己的 :D 除了这里的 Regex 方法,这是 Linq 方法在幕后所做的 - 循环和切碎 - 只是更容易阅读。我确实喜欢上面的批处理方法,这对我来说是一个新方法:)
  • 这甚至不会编译,因为length 不是System.String 的成员。
【解决方案4】:

丑陋但垃圾少:

private string InsertStrings(string s, int insertEvery, char insert)
{
    char[] ins = s.ToCharArray();
    int length = s.Length + (s.Length / insertEvery);
    if (ins.Length % insertEvery == 0)
    {
        length--;
    }
    var outs = new char[length];
    long di = 0;
    long si = 0;
    while (si < s.Length - insertEvery)
    {
        Array.Copy(ins, si, outs, di, insertEvery);
        si += insertEvery;
        di += insertEvery;
        outs[di] = insert;
        di ++;
    }
    Array.Copy(ins, si, outs, di, ins.Length - si);
    return new string(outs);
}

字符串重载:

private string InsertStrings(string s, int insertEvery, string insert)
{
    char[] ins = s.ToCharArray();
    char[] inserts = insert.ToCharArray();
    int insertLength = inserts.Length;
    int length = s.Length + (s.Length / insertEvery) * insert.Length;
    if (ins.Length % insertEvery == 0)
    {
        length -= insert.Length;
    }
    var outs = new char[length];
    long di = 0;
    long si = 0;
    while (si < s.Length - insertEvery)
    {
        Array.Copy(ins, si, outs, di, insertEvery);
        si += insertEvery;
        di += insertEvery;
        Array.Copy(inserts, 0, outs, di, insertLength);
        di += insertLength;
    }
    Array.Copy(ins, si, outs, di, ins.Length - si);
    return new string(outs);
}

【讨论】:

    【解决方案5】:

    还有另一种正则表达式方法:

    var str = "111111110000000011111111000000001111111100000000";
    # for .NET 4
    var res = String.Join(",",Regex.Matches(str, @"\d{8}").Cast<Match>());
    
    # for .NET 3.5
    var res = String.Join(",", Regex.Matches(str, @"\d{8}")
                .OfType<Match>()
                .Select(m => m.Value).ToArray());
    

    【讨论】:

    • 我喜欢这种方法,因为“部分是可以理解的”,即使在 .NET 3.5 中需要更多的软糖
    • 感谢您的补充 :) - 我一直忘记检查框架兼容性。
    • 此代码删除字符。分隔符将替换为字符串,字符串将丢失。
    【解决方案6】:

    如果我正确理解您的最后一个要求(我不清楚您是否需要中间逗号分隔的字符串),您可以这样做:

    var enumerable = "111111110000000011111111000000001111111100000000".Batch(8).Reverse();
    

    通过使用morelinq

    【讨论】:

    • 如果只有Batch 是标准的:( 无论如何,了解morelinq 是很重要的。
    【解决方案7】:

    使用 LINQ 的一种方式:

    string data = "111111110000000011111111000000001111111100000000";
    const int separateOnLength = 8;
    
    string separated = new string(
        data.Select((x,i) => i > 0 && i % separateOnLength == 0 ? new [] { ',', x } : new [] { x })
            .SelectMany(x => x)
            .ToArray()
        );
    

    【讨论】:

    • 此代码从右到左插入分隔符。而不是从左到右
    【解决方案8】:

    这也是我的两分钱。使用 StringBuilder 的实现:

            public static string AddChunkSeparator (string str, int chunk_len, char separator)
            {
                if (str == null || str.Length < chunk_len) {
                    return str;
                }
                StringBuilder builder = new StringBuilder();
                for (var index = 0; index < str.Length; index += chunk_len) {
                    builder.Append(str, index, chunk_len);
                    builder.Append(separator);
                }
                return builder.ToString();
            }
    

    你可以这样称呼它:

    string data = "111111110000000011111111000000001111111100000000";
    string output = AddChunkSeparator(data, 8, ',');
    

    【讨论】:

    • 如果 str 为 null 或者它比 chunk_len 短,此方法将失败
    【解决方案9】:

    我使用 PatternMatcher 按以下方式完成:

    fun addAnyCharacter(input: String, insertion: String, interval: Int): String {
      val pattern = Pattern.compile("(.{$interval})", Pattern.DOTALL)
      val matcher = pattern.matcher(input)
      return matcher.replaceAll("$1$insertion")
    }
    

    地点:

    input 表示输入字符串。检查结果部分。

    insertion 表示在这些字符之间插入字符串。例如逗号(,)、开始(*)、哈希(#)。

    interval 表示要在哪个间隔添加插入字符。

    input 表示输入字符串。检查结果部分。检查结果部分;在这里,我在每 4 个字符处添加了插入。

    结果:

    I/P: 1234XXXXXXXX5678 O/P: 1234 XXXX XXXX 5678

    I/P: 1234567812345678 O/P: 1234 5678 1234 5678

    I/P: ABCDEFGHIJKLMNOP O/P: ABCD EFGH IJKL MNOP

    希望这会有所帮助。

    【讨论】:

      【解决方案10】:

      这在不复制数组的情况下要快得多(此版本每 3 位插入空格,但您可以根据需要进行调整)

      public string GetString(double valueField)
      {
          char[] ins = valueField.ToString().ToCharArray();
          int length = ins.Length + (ins.Length / 3);
          if (ins.Length % 3 == 0)
          {
              length--;
          }
          char[] outs = new char[length];
      
          int i = length - 1;
          int j = ins.Length - 1;
          int k = 0;
          do
          {
              if (k == 3)
              {
                  outs[i--] = ' ';
                  k = 0;
              }
              else
              {
                  outs[i--] = ins[j--];
                  k++;
              }           
          }
          while (i >= 0);
      
          return new string(outs);
      }
      

      【讨论】:

      • 我不明白这个。 valueField 是双倍的?您将输入字符串转换为双精度,以便在函数中使用它,然后将其重新转换为字符串和 charArray?你介意评论一下代码吗?
      • 我没有输入字符串。我只是有一个双倍值,这就是为什么valueFiled 是双倍的。如果你有字符串值,那么你可以创建valueFiled 字符串并将第一行更改为char[] ins = valueField.ToCharArray();
      【解决方案11】:

      聚会有点晚了,但这里有一个简化的 LINQ 表达式,用于将输入字符串 x 分成由另一个字符串分隔的 nsep

      string sep = ",";
      int n = 8;
      string result = String.Join(sep, x.InSetsOf(n).Select(g => new String(g.ToArray())));
      

      这里发生的事情的简要概述:

      • x 被视为 IEnumberable&lt;char&gt;,这就是 InSetsOf 扩展方法的用武之地。
      • InSetsOf(n) 将字符组合成一个IEnumerable IEnumerable -- 外部分组中的每个条目都包含一个内部n 字符组。
      • Select 方法中,每组n 字符都使用String() 构造函数转换回字符串,该构造函数采用chars 数组。
      • Select 的结果现在是一个IEnumerable&lt;string&gt;,它被传递到String.Join 以交错sep 字符串,就像任何其他示例一样。

      【讨论】:

        【解决方案12】:

        如果您打算在不使用正则表达式或模式匹配方法的情况下创建自己的函数来实现这一目标,您可以创建一个像这样的简单函数:

        String formatString(String key, String seperator, int afterEvery){
                String formattedKey = "";
                for(int i=0; i<key.length(); i++){
                    formattedKey += key.substring(i,i+1);
                    if((i+1)%afterEvery==0)
                        formattedKey += seperator;
                }
                if(formattedKey.endsWith("-"))
                    formattedKey = formattedKey.substring(0,formattedKey.length()-1);
                return formattedKey;
            }
        

        这样调用方法

        formatString("ABCDEFGHIJKLMNOPQRST", "-", 4)
        

        将导致返回字符串为this

        ABCD-EFGH-IJKL-MNOP-QRST
        

        【讨论】:

          【解决方案13】:

          我的答案已经晚了,但你可以使用这个:

              static string PutLineBreak(string str, int split)
              {
                  for (int a = 1; a <= str.Length; a++)
                  {
                      if (a % split == 0)
                          str = str.Insert(a, "\n");
                  }
          
                  return str;
              }
          

          【讨论】:

            【解决方案14】:

            对于每 1 个字符,您可以这样做:

            string.Join(".", "1234".ToArray()) //result: 1.2.3.4
            

            【讨论】:

            • 这个模式对我很有帮助
            猜你喜欢
            • 2016-03-31
            • 2020-08-13
            • 2022-01-18
            • 2023-02-25
            • 2015-12-04
            • 2022-01-15
            • 1970-01-01
            相关资源
            最近更新 更多