【问题标题】:String.Replace is not working as expectedString.Replace 没有按预期工作
【发布时间】:2017-06-14 06:53:32
【问题描述】:

我有一个程序

    public void TestMethod2()
    {
        string[] keywords =
        {
            "SELECT", "FROM", "WHERE", "GROUP", "HAVING", "ORDER", "LEFT",  "RIGHT", "JOIN", "INNER", "OUTER", "ASC",
            "DESC", "AND", "OR","IN", "BETWEEN", "BY", "NOT", "ON", "AS", "CASE", "WHEN", "ELSE", "UPDATE", "SET"
        };

        var actualString = "SELECT * FROm A Join B On C in D case e join t left outer join inner join right join";

        foreach (var text in actualString.Split(' '))
        {
            var isExists = keywords.Any(x => x.Equals(text, StringComparison.OrdinalIgnoreCase));

            if (!isExists)
            {
                continue;
            }

            actualString = actualString.Replace(text, text.ToUpper());
        }


        var expectedString = "SELECT * FROM A JOIN B ON C IN D CASE e JOIN t LEFT OUTER JOIN INNER JOIN RIGHT JOIN";

    }

我是 C# 的新手。我不清楚为什么 Replace() 方法没有按预期工作。它正在显示输出 SELECT * FROM A JOIN B ON C IN D CASE e join t LEFT OUTER JOIN INNER JOIN RIGHT JOIN

有人能告诉我为什么 Replace() 会这样吗? 提前致谢。

【问题讨论】:

    标签: c# string


    【解决方案1】:

    我建议使用Regex.Replace 而不是只使用String.Replace

     \bKeyWord\b 
    

    模式 当且仅当它是一个整个单词时,将子字符串视为关键字:

     select horror 
       from torro 
      where corner = 1 
         or ordain = 2
    

    应该变成

     SELECT horror -- even if horror has two "or"
       FROM torro  -- even if torro has two "or"
      WHERE corner = 1 -- even if corner contains "or"
         OR ordain = 2 -- even if ordain contains "or"
    

    实施:

    string[] keywords = {
      "SELECT", "FROM", "WHERE", "GROUP", "HAVING", "ORDER", "LEFT",  "RIGHT",
      "JOIN", "INNER", "OUTER", "ASC", "DESC", "AND", "OR","IN", "BETWEEN", 
      "BY", "NOT", "ON", "AS", "CASE", "WHEN", "ELSE", "UPDATE", "SET"
    };
    
    var actualString = 
      "SELECT * FROm A Join B On C in D case e join t left outer join inner join right join";
    
    foreach (var keyword in keywords)
      actualString = Regex.Replace(
        actualString,
        @"\b" + Regex.Escape(keyword) + @"\b",
        keyword.ToUpper(),
        RegexOptions.IgnoreCase); 
    

    【讨论】:

      【解决方案2】:

      从这里的答案中得到了一个清晰的想法。最后通过将 foreach 更改为 for 循环来解决这个问题。谢谢你们。

      public void TestMethod2()
      {
          string[] keywords =
          {
              "SELECT", "FROM", "WHERE", "GROUP", "HAVING", "ORDER", "LEFT",  "RIGHT", "JOIN", "INNER", "OUTER", "ASC",
              "DESC", "AND", "OR","IN", "BETWEEN", "BY", "NOT", "ON", "AS", "CASE", "WHEN", "ELSE", "UPDATE", "SET"
          };
      
          var actualString = "SELECT * FROm A Join B On C in D case e join t left outer join inner join right join";
      
          var cnt = sqlTest.Split(' ').Count();
          for (int i = 0; i < cnt; i++)
          {
              var text = sqlTest.Split(' ')[i];
              var isExists = keywords.Any(x => x.Equals(text, StringComparison.OrdinalIgnoreCase));
      
              if (!isExists)
              {
                  continue;
              }
      
              actualString = actualString.Replace(text, text.ToUpper());
          }
      
      
          var expectedString = "SELECT * FROM A JOIN B ON C IN D CASE e JOIN t LEFT OUTER JOIN INNER JOIN RIGHT JOIN";
      
      }
      

      【讨论】:

        【解决方案3】:

        它的行为符合预期。这是一行一行的输出:

        [SELECT] -> SELECT * FROm A Join B On C in D case e join t left outer join inner join right join [FROm] -> SELECT * FROM A Join B On C in D case e join t left outer join inner join right join [Join] -> SELECT * FROM A JOIN B On C in D case e join t left outer join inner join right join [On] -> SELECT * FROM A JOIN B ON C in D case e join t left outer join inner join right join [in] -> SELECT * FROM A JOIN B ON C IN D case e join t left outer join INner join right join [case] -> SELECT * FROM A JOIN B ON C IN D CASE e join t left outer join INner join right join [join] -> SELECT * FROM A JOIN B ON C IN D CASE e join t left external join INner join right join [left] -> SELECT * FROM A JOIN B ON C IN D CASE e join t LEFT external join INner join right join [outer] -> SELECT * FROM A JOIN B ON C IN D CASE e join t LEFT OUTER JOIN INNER JOIN right join [join] -> SELECT * FROM A JOIN B ON C IN D CASE e join t LEFT OUTER JOIN INNER JOIN right join [inner] -> SELECT * FROM A JOIN B ON C IN D CASE e join t LEFT OUTER JOIN INner join right join [join] -> SELECT * FROM A JOIN B ON C IN D CASE e join t LEFT OUTER JOIN INNER JOIN right join [right] -> SELECT * FROM A JOIN B ON C IN D CASE e join t LEFT OUTER JOIN INNER JOIN RIGHT JOIN [join] -> SELECT * FROM A JOIN B ON C IN D CASE e join t LEFT OUTER JOIN INNER JOIN RIGHT JOIN

        您可以在第 5 行看到当 inIN 替换时;然后 join 被替换为 joIN

        然后,发生的事情是您对 Keywords.Any 的调用正常工作,并且匹配 joinjoIN,但是,replace 调用仍然区分大小写,替换不会发生。

        替换是 C# 区分大小写,不幸的是,.NET 不提供不区分大小写的版本;但是有一些解决方案。

        检查 this link 以获取不区分大小写替换的实现。

        【讨论】:

        • 谢谢@Thomas。明白了。
        【解决方案4】:

        问题是您已经替换了联接中的 IN。因此,当您想用 JOIN 替换 join 时,比较失败。 (加入!= 加入)

        【讨论】:

          【解决方案5】:

          如果你调试它,你会注意到你的关键字“in”替换了第二个连接,所以你得到了 join。稍后您的文本变量将尝试将“join”替换为“JOIN”,但它不会找到“join”,因为它的一部分是大写的。

          【讨论】:

          • 因为这是关于一个 sql 字符串并且那些不以 'in' 或其他 sql 单词分数开头或结尾的字符串,一个简单的解决方法是用空格包围 needle 和 haystack。另外:请注意答案的前三个字!
          • @Zbigniew - 实际上我的错误是我认为 foreach 像 for 循环一样工作。现在我知道了。谢谢。
          • @NoorAshuvo 我看不出它会有什么帮助。
          猜你喜欢
          • 2016-01-03
          • 1970-01-01
          • 2021-10-19
          • 2020-03-18
          • 2012-06-14
          • 2014-11-15
          • 1970-01-01
          • 2012-07-02
          • 2011-09-07
          相关资源
          最近更新 更多