2

I have a program

    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";

    }

I am a newbie in C#. I am not clear why the Replace() method is not working as expected. It is showing the output SELECT * FROM A JOIN B ON C IN D CASE e joIN t LEFT OUTER joIN INner joIN RIGHT joIN

Can someone please enlighten me why Replace() is behaving like this? Thanks in advance.

CSharpie
  • 9,195
  • 4
  • 44
  • 71
Noor A Shuvo
  • 2,639
  • 3
  • 23
  • 48

5 Answers5

8

If you debug it you will notice that your keyword "in" replaces second join so you get joIN. Later your text variable will try to replace "join" with "JOIN" but it won't find "join" because part of it was uppercased.

MistyK
  • 6,055
  • 2
  • 42
  • 76
  • 1
    Since this is about an sql string and those don't start or end with an 'in' or other sql word fraction, a simple fix is to surround both needle and haystack with spaces. Also: Do note the first three words of the answer! – TaW Jan 28 '17 at 19:01
  • @Zbigniew - Actually my mistake was I thought foreach works like for loop. Now I got it. thanks. – Noor A Shuvo Jan 28 '17 at 20:03
  • @NoorAShuvo I can't see how it would help. – MistyK Jan 29 '17 at 10:22
2

It is behaving as expected. Here is the output line by line:

[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 outer joIN INner joIN right joIN
[left]   -> SELECT * FROM A JOIN B ON C IN D CASE e joIN t LEFT outer 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

You can see that when in gets replaced by IN, at line 5; then join gets replaced by joIN

But then, what happen is that your call to Keywords.Any works properly, and matches join and joIN, however, the replace call is still case sensitive and the replace will not take place.

Replace is C# is case sensitive and, unfortunately, .NET doesn't offer a case insensitive version; but there are solutions floating around.

Check this link for an implementation of a case insensitive replace.

Community
  • 1
  • 1
Thomas
  • 10,933
  • 14
  • 65
  • 136
0

The problem is that you already replace the IN in join. Therefore the comparison fails when you want to replace join with JOIN. (joIN != join)

Thomas Voß
  • 1,145
  • 8
  • 20
0

Got a clear idea from the answers here.Finally solve that by changing the foreach with for loop. Thank you all.

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";

}
Noor A Shuvo
  • 2,639
  • 3
  • 23
  • 48
0

I suggest using Regex.Replace instead of just String.Replace with

 \bKeyWord\b 

pattern in order treating a substring as a keyword if and only if it is a whole word:

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

should be turned into

 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"

Implementation:

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); 
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215