【问题标题】:Splitting a string and keeping the delimiters拆分字符串并保留分隔符
【发布时间】:2014-05-25 09:30:04
【问题描述】:

大家好,我一直在尝试查看是否可以拆分字符串并将分隔符保留为新字符串数组中的单独元素,但发现这很困难。这正是我想要实现的......

如果我有字符串"8*(4+x)+7"...

我将用运算符和括号分开,得到类似..."8","*", "(", "4", "+", "x", ")", "+", "7"....

我在这里阅读了很多关于如何使用 Regex.Split 做到这一点的答案,并尝试了其中的许多,但我没有得到我想要的。

【问题讨论】:

  • 您不需要拆分字符串。判断是否不一定要使用拆分?
  • 我没有注意到任何分裂。看起来你只想要一个字符数组。您已经可以使用foreach 枚举字符串或调用MyString.ToCharArray()
  • @Silvermind - 他可能希望像“10”这样的数字保留为单独的字符串。
  • Hassan,这是必要的,因为数字可能超过 1 位,而且变量 x 可能包含超过 1 个字符,因此需要一个字符串数组,因此需要拆分。

标签: c# regex string split


【解决方案1】:

不要拆分 - 匹配!

var equation = "8 * (42+xyz)+7";
var tokens = Regex.Matches(equation, @"\d+|\w+|\S")
    .OfType<Match>()
    .Select(m => m.Value);

这个regular expression pattern 匹配一个

  • 一系列数字 - 例如8, 42
  • 一系列单词字符 - 例如xyz(它也将匹配 x_2
  • 单个非空白字符 - 例如*, (

匹配执行多次(通过Matches),每个成功匹配的值都被选入生成的IEnumerable&lt;string&gt;

与传统的拆分不同,这种方法没有明确的分隔符,因为分隔仅由每次匹配停止和下一次匹配开始的位置确定。这也是跳过空白的原因:它只是不匹配。

要明确指定运算符或“分隔符”,只需将\S(匹配任何非空白字符)替换为[+*()](仅匹配指定的运算符和括号)之类的模式。

虽然这是一个完成请求任务的非常简单的标记器,但在此阶段添加额外的lexeme 信息通常很有用。

【讨论】:

  • 它会返回什么?一个字符串数组?以及在哪里列出分隔符
  • 它将返回一个IEnumerable&lt;string&gt;。这种方法没有分隔符 - 只是每个匹配将“吃掉”多少,因为分隔取决于每个匹配停止的位置。
  • 谢谢,但如果我有一个标识符 X2,这也不起作用,它将分隔 x 和 2
  • @user3442256 这会将1+x2 标记为1,+,x2 - 它不会分隔以下字母的数字。如果它不起作用,请提供使用的输入,以便我也能看到!如果您需要匹配 2x 作为标识符(我建议 not 这样做),那么只需使用 \w+|\S 作为正则表达式(阅读:匹配一系列单词字符,或单个非空格字符)。
  • @user3442256 虽然我故意保持正则表达式规则简单,并将其作为单一方法方法,但“正确”的标记器将为每种类型的标记提供 特定 规则(例如数字、变量、运算符),可能使用最长匹配优先级,并报告不匹配的数据。
【解决方案2】:

这行得通:

Func<IEnumerable<string>, IEnumerable<char>, IEnumerable<string>> split = null;
split = (ss, cs) =>
{
    if (!cs.Any())
    {
        return ss;
    }
    else
    {
        var c = cs.First();
        return ss.SelectMany(s0 =>
        {
            var parts = s0.Split(c);
            return split(
                parts
                    .Take(1)
                    .Concat(
                        parts
                            .Skip(1)
                            .SelectMany(p => new [] { new string(c, 1), p })),
                cs.Skip(1));
        })
        .Where(s0 => !String.IsNullOrWhiteSpace(s0));
    }
};

(请注意,split 的双重赋值是必要的,因为这是一个递归函数。)

所以,如果我从这个开始:

var s = "80*(45+xy)+27";
var separators = "*+-/()";

我可以这样做:

var result = split(new [] { s }, separators);

我最终得到了这个:

【讨论】:

  • 拜托我真的是编程新手,所以如果我的一些问题听起来很愚蠢,我很抱歉......什么是 CS 和 SS?
  • @user3442256 - 它们是匿名方法split 的参数。就像我声明了一个带有签名IEnumerable&lt;string&gt; split(IEnumerable&lt;string&gt; ss, IEnumerable&lt;char&gt; cs) 的新方法一样。
【解决方案3】:
string str = "8400*(413+x)+700";
List<string> lstArray = new List<string>();

 for(int i=0; i<str.Length; i++)
 {
      if (Char.IsNumber(str[i]))
      {
           string sNum = str[i].ToString();

           if ((i + 1) < str.Length)
           {
                 for (int k = i+1; k < str.Length; k++)
                 {
                     if (Char.IsNumber(str[k]) == true)
                     {
                         sNum += str[k].ToString();
                         i = i + 1;
                     }
                     else
                        break;
                  }
           }
           lstArray.Add(sNum);
       }
       else if (Char.IsSymbol(str[i]))
       {
            lstArray.Add(str[i].ToString());                                  
       }
       else if (Char.IsLetter(str[i]))
       {
           string sLetter = str[i].ToString();

           if ((i + 1) < str.Length)
           {
              for (int k = i + 1; k < str.Length; k++)
              {
                  if (Char.IsLetter(str[k]) == true)
                  {
                      sLetter += str[k].ToString();
                      i = i + 1;
                  }
                  else
                      break;
              }
          }
          lstArray.Add(sLetter);
      }
      else if (Char.IsPunctuation(str[i]))
      {                   
          lstArray.Add(str[i].ToString());
      }
  }

上面的代码应该可以工作。 打印值之间有逗号的列表应该是这样的:

 Console.WriteLine(string.Join(",", lstArray.ToArray()));

这里是输入和输出示例:

 //Input     
 8400*(413+xyz)+700

 //Output
 8400,*,(,413,+,xyz,),+,700

或者你可以遍历lstArray:

 foreach(string s in lstArray)
     Console.WriteLine(s);

【讨论】:

  • @user2864740 可以解释一下吗?
  • 就像我说的数字可能包括像 10 这样的数字所以这不起作用
  • @user2864740,请查看更新后的答案。感谢指正。
猜你喜欢
  • 2016-11-26
  • 2022-11-03
  • 1970-01-01
  • 2018-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多