【问题标题】:C#: Need to split a string into a string[] and keeping the delimiter (also a string) at the beginning of the stringC#:需要将一个字符串拆分成一个字符串[],并在字符串的开头保留分隔符(也是一个字符串)
【发布时间】:2021-01-31 00:02:22
【问题描述】:

我觉得我太笨了,无法解决这个问题……

我有一些公式需要从一种语法“翻译”到另一种语法。 假设我有一个这样的公式(这是一个简单的公式,其他公式中有很多“天花板”):

string formulaString = "If([Param1] = 0, 1, Ceiling([Param2] / 0.55) * [Param3])";

我需要将“Ceiling()”替换为“Ceiling(;1)”(基本上,在“)”之前插入“;1”)。 我的尝试是在“Ceiling(”处拆分 fomulaString,这样我就可以遍历字符串数组并将字符串插入到正确的索引处(计算每个“(”和“)”以获得正确的索引)

到目前为止我所拥有的:

//splits correct, but loses "CEILING("
string[] parts = formulaString.Split(new[] { "CEILING(" }, StringSplitOptions.None);
//splits almost correct, "CEILING(" is in another group
string[] parts = Regex.Split(formulaString, @"(CEILING\()");
//splits almost every letter
string[] parts = Regex.Split(formulaString, @"(?=[(CEILING\()])");

当一切都完成后,我将字符串连接起来,这样我又得到了完整的公式。

我必须将什么设置为正则表达式模式才能实现此示例? (或任何其他对我有帮助的方法)

part1 = "If([Param1] = 0, 1, ";
part2 = "Ceiling([Param2] / 0.55) * [Param3])";
//part3 = next "CEILING(" in a longer formula and so on...

【问题讨论】:

  • 你可以像这样使用String.Join(char separator, string[] value) 加入字符串:String.Join ("CEILING(", parts) 而不是连接它。
  • 我有一些公式需要从一种语法“翻译”到另一种语法:根据转换的整体复杂性,可能值得一看 @ 987654322@.
  • 对于语法更简单的语言,可能值得自己使用 SprachePidgin 之类的东西构建解析器
  • 你几乎明白了:(?=Ceiling) 在正则表达式中使用正前瞻零断言。 regular-expressions.info/lookaround.html
  • 感谢所有评论员,我会进一步查看您提供给我的所有链接。由于语法翻译相对容易(只需在右括号前插入一些字符串),我将坚持使用 Regex.Split()

标签: c# regex split


【解决方案1】:

正如我在评论中提到的,你几乎明白了:(?=Ceiling)。不幸的是,这对于您的用例来说是不完整的。

我需要将“Ceiling()”替换为“Ceiling(;1)”(基本上,在“)”之前插入“;1”)。

这取决于你的正则表达式引擎(例如 JS):

string[] parts = Regex.Split(formulaString, @"(?<=Ceiling\([^)]*(?=\)))");
string modifiedFormula = String.join("; 1", parts);

正则表达式

(?<=Ceiling\([^)]*(?=\)))
(?<=                    )   Positive lookbehind
    Ceiling\(               Search for literal "Ceiling("
             [^)]           Match any char which is not ")" ..
                 *          .. 0 or more times
                  (?=\))    Positive lookahead for ")", effectively making us stop before the ")"

这个正则表达式是一个零断言,因此不会丢失任何内容,它会在每个“Ceiling()”中的最后一个“)”之前切断你的字符串。

只要您嵌套了“Ceiling()”,此解决方案就会中断。那么您唯一的解决方案就是为 same reasons why you can't parse markup with regex 编写自己的解析器。

【讨论】:

  • 非常感谢您的解释。我刚刚检查了大约 300 个必须翻译的公式,是的,有一些嵌套的“Ceiling()”。所以我必须为此编写一个解析器。
【解决方案2】:
Regex.Replace(formulaString, @"(?<=Ceiling\()(.*?)(?=\))","$1; 1");

注意:这不适用于嵌套的“天花板”,但它适用于Ceiling(),它也不适用于Ceiling(AnotherFunc(x))。为此,您需要以下内容:

Regex.Replace(formulaString, @"(?<=Ceiling\()((.*\((?>[^()]+|(?1))*\))*|[^\)]*)(\))","$1; 1$3");

但我无法让它与 .NET 一起使用,只能在 JavaScript 中使用。

【讨论】:

    【解决方案3】:

    这是我的解决方案:

    private string ConvertCeiling(string formula)
    {
        int ceilingsCount = formula.CountOccurences("Ceiling(");
    
        int startIndex = 0;
        int bracketCounter;
        for (int i = 0; i < ceilingsCount; i++)
        {
            startIndex = formula.IndexOf("Ceiling(", startIndex);
    
            bracketCounter = 0;
            for (int j = 0; j < formula.Length; j++)
            {
                if (j < startIndex) continue;
    
                var c = formula[j];
                if (c == '(')
                {
                    bracketCounter++;
                }
                if (c == ')')
                {
                    bracketCounter--;
                    if (bracketCounter == 0)
                    {
                        // found end
                        formula = formula.Insert(j, "; 1");
                        startIndex++;
                        break;
                    }
                }
            }
        }
        return formula;
    }
    

    和CountOccurence:

    public static int CountOccurences(this string value, string parameter)
    {
        int counter = 0;
        int startIndex = 0;
        int indexOfCeiling;
        do
        {
            indexOfCeiling = value.IndexOf(parameter, startIndex);
            if (indexOfCeiling < 0)
            {
                break;
            }
            else
            {
                startIndex = indexOfCeiling + 1;
                counter++;
            }
    
        } while (true);
        return counter;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多