Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>When I ran into this on a contract, I had no other option than to have a 100% compliant TransactSQL LIKE function. Below is the result - a static function and a string extension method. I'm sure it can be optimized further, but it's pretty fast and passed my long list of test scenarios. Hope it helps someone!</p> <pre><code>using System; using System.Collections.Generic; namespace SqlLikeSample { public class TestSqlLikeFunction { static void Main(string[] args) { TestSqlLikePattern(true, "%", ""); TestSqlLikePattern(true, "%", " "); TestSqlLikePattern(true, "%", "asdfa asdf asdf"); TestSqlLikePattern(true, "%", "%"); TestSqlLikePattern(false, "_", ""); TestSqlLikePattern(true, "_", " "); TestSqlLikePattern(true, "_", "4"); TestSqlLikePattern(true, "_", "C"); TestSqlLikePattern(false, "_", "CX"); TestSqlLikePattern(false, "[ABCD]", ""); TestSqlLikePattern(true, "[ABCD]", "A"); TestSqlLikePattern(true, "[ABCD]", "b"); TestSqlLikePattern(false, "[ABCD]", "X"); TestSqlLikePattern(false, "[ABCD]", "AB"); TestSqlLikePattern(true, "[B-D]", "C"); TestSqlLikePattern(true, "[B-D]", "D"); TestSqlLikePattern(false, "[B-D]", "A"); TestSqlLikePattern(false, "[^B-D]", "C"); TestSqlLikePattern(false, "[^B-D]", "D"); TestSqlLikePattern(true, "[^B-D]", "A"); TestSqlLikePattern(true, "%TEST[ABCD]XXX", "lolTESTBXXX"); TestSqlLikePattern(false, "%TEST[ABCD]XXX", "lolTESTZXXX"); TestSqlLikePattern(false, "%TEST[^ABCD]XXX", "lolTESTBXXX"); TestSqlLikePattern(true, "%TEST[^ABCD]XXX", "lolTESTZXXX"); TestSqlLikePattern(true, "%TEST[B-D]XXX", "lolTESTBXXX"); TestSqlLikePattern(true, "%TEST[^B-D]XXX", "lolTESTZXXX"); TestSqlLikePattern(true, "%Stuff.txt", "Stuff.txt"); TestSqlLikePattern(true, "%Stuff.txt", "MagicStuff.txt"); TestSqlLikePattern(false, "%Stuff.txt", "MagicStuff.txt.img"); TestSqlLikePattern(false, "%Stuff.txt", "Stuff.txt.img"); TestSqlLikePattern(false, "%Stuff.txt", "MagicStuff001.txt.img"); TestSqlLikePattern(true, "Stuff.txt%", "Stuff.txt"); TestSqlLikePattern(false, "Stuff.txt%", "MagicStuff.txt"); TestSqlLikePattern(false, "Stuff.txt%", "MagicStuff.txt.img"); TestSqlLikePattern(true, "Stuff.txt%", "Stuff.txt.img"); TestSqlLikePattern(false, "Stuff.txt%", "MagicStuff001.txt.img"); TestSqlLikePattern(true, "%Stuff.txt%", "Stuff.txt"); TestSqlLikePattern(true, "%Stuff.txt%", "MagicStuff.txt"); TestSqlLikePattern(true, "%Stuff.txt%", "MagicStuff.txt.img"); TestSqlLikePattern(true, "%Stuff.txt%", "Stuff.txt.img"); TestSqlLikePattern(false, "%Stuff.txt%", "MagicStuff001.txt.img"); TestSqlLikePattern(true, "%Stuff%.txt", "Stuff.txt"); TestSqlLikePattern(true, "%Stuff%.txt", "MagicStuff.txt"); TestSqlLikePattern(false, "%Stuff%.txt", "MagicStuff.txt.img"); TestSqlLikePattern(false, "%Stuff%.txt", "Stuff.txt.img"); TestSqlLikePattern(false, "%Stuff%.txt", "MagicStuff001.txt.img"); TestSqlLikePattern(true, "%Stuff%.txt", "MagicStuff001.txt"); TestSqlLikePattern(true, "Stuff%.txt%", "Stuff.txt"); TestSqlLikePattern(false, "Stuff%.txt%", "MagicStuff.txt"); TestSqlLikePattern(false, "Stuff%.txt%", "MagicStuff.txt.img"); TestSqlLikePattern(true, "Stuff%.txt%", "Stuff.txt.img"); TestSqlLikePattern(false, "Stuff%.txt%", "MagicStuff001.txt.img"); TestSqlLikePattern(false, "Stuff%.txt%", "MagicStuff001.txt"); TestSqlLikePattern(true, "%Stuff%.txt%", "Stuff.txt"); TestSqlLikePattern(true, "%Stuff%.txt%", "MagicStuff.txt"); TestSqlLikePattern(true, "%Stuff%.txt%", "MagicStuff.txt.img"); TestSqlLikePattern(true, "%Stuff%.txt%", "Stuff.txt.img"); TestSqlLikePattern(true, "%Stuff%.txt%", "MagicStuff001.txt.img"); TestSqlLikePattern(true, "%Stuff%.txt%", "MagicStuff001.txt"); TestSqlLikePattern(true, "_Stuff_.txt_", "1Stuff3.txt4"); TestSqlLikePattern(false, "_Stuff_.txt_", "1Stuff.txt4"); TestSqlLikePattern(false, "_Stuff_.txt_", "1Stuff3.txt"); TestSqlLikePattern(false, "_Stuff_.txt_", "Stuff3.txt4"); Console.ReadKey(); } public static void TestSqlLikePattern(bool expectedResult, string pattern, string testString) { bool result = testString.SqlLike(pattern); if (expectedResult != result) { Console.ForegroundColor = ConsoleColor.Red; System.Console.Out.Write("[SqlLike] FAIL"); } else { Console.ForegroundColor = ConsoleColor.Green; Console.Write("[SqlLike] PASS"); } Console.ForegroundColor = ConsoleColor.White; Console.WriteLine(": \"" + testString + "\" LIKE \"" + pattern + "\" == " + expectedResult); } } public static class SqlLikeStringExtensions { public static bool SqlLike(this string s, string pattern) { return SqlLikeStringUtilities.SqlLike(pattern, s); } } public static class SqlLikeStringUtilities { public static bool SqlLike(string pattern, string str) { bool isMatch = true, isWildCardOn = false, isCharWildCardOn = false, isCharSetOn = false, isNotCharSetOn = false, endOfPattern = false; int lastWildCard = -1; int patternIndex = 0; List&lt;char&gt; set = new List&lt;char&gt;(); char p = '\0'; for (int i = 0; i &lt; str.Length; i++) { char c = str[i]; endOfPattern = (patternIndex &gt;= pattern.Length); if (!endOfPattern) { p = pattern[patternIndex]; if (!isWildCardOn &amp;&amp; p == '%') { lastWildCard = patternIndex; isWildCardOn = true; while (patternIndex &lt; pattern.Length &amp;&amp; pattern[patternIndex] == '%') { patternIndex++; } if (patternIndex &gt;= pattern.Length) p = '\0'; else p = pattern[patternIndex]; } else if (p == '_') { isCharWildCardOn = true; patternIndex++; } else if (p == '[') { if (pattern[++patternIndex] == '^') { isNotCharSetOn = true; patternIndex++; } else isCharSetOn = true; set.Clear(); if (pattern[patternIndex + 1] == '-' &amp;&amp; pattern[patternIndex + 3] == ']') { char start = char.ToUpper(pattern[patternIndex]); patternIndex += 2; char end = char.ToUpper(pattern[patternIndex]); if (start &lt;= end) { for (char ci = start; ci &lt;= end; ci++) { set.Add(ci); } } patternIndex++; } while (patternIndex &lt; pattern.Length &amp;&amp; pattern[patternIndex] != ']') { set.Add(pattern[patternIndex]); patternIndex++; } patternIndex++; } } if (isWildCardOn) { if (char.ToUpper(c) == char.ToUpper(p)) { isWildCardOn = false; patternIndex++; } } else if (isCharWildCardOn) { isCharWildCardOn = false; } else if (isCharSetOn || isNotCharSetOn) { bool charMatch = (set.Contains(char.ToUpper(c))); if ((isNotCharSetOn &amp;&amp; charMatch) || (isCharSetOn &amp;&amp; !charMatch)) { if (lastWildCard &gt;= 0) patternIndex = lastWildCard; else { isMatch = false; break; } } isNotCharSetOn = isCharSetOn = false; } else { if (char.ToUpper(c) == char.ToUpper(p)) { patternIndex++; } else { if (lastWildCard &gt;= 0) patternIndex = lastWildCard; else { isMatch = false; break; } } } } endOfPattern = (patternIndex &gt;= pattern.Length); if (isMatch &amp;&amp; !endOfPattern) { bool isOnlyWildCards = true; for (int i = patternIndex; i &lt; pattern.Length; i++) { if (pattern[i] != '%') { isOnlyWildCards = false; break; } } if (isOnlyWildCards) endOfPattern = true; } return isMatch &amp;&amp; endOfPattern; } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload