C# 版本的 SQL LIKE

Posted

技术标签:

【中文标题】C# 版本的 SQL LIKE【英文标题】:C# Version Of SQL LIKE 【发布时间】:2011-07-21 23:37:45 【问题描述】:

有没有办法在 C# 中搜索字符串中的模式?

像 Sql LIKE 这样的东西会非常有用。

【问题讨论】:

How to do SQL Like % in Linq? 的可能重复项 @jgauffin,不是重复的,因为在 Linq 中有几种 SQL Like 方法不适用于 C# 的其余部分 因此“可能”重复;) 【参考方案1】:

正则表达式允许LIKE 允许的所有内容,甚至更多,但语法完全不同。但是,由于LIKE 的规则非常简单(其中% 表示零个或多个字符,_ 表示一个字符),并且LIKE 参数和正则表达式都用字符串表示,我们可以创建一个正则表达式,它接受一个LIKE 参数(例如abc_ef% *usd)并将其转换为等效的正则表达式(例如\Aabc.ef.* \*usd\z):

@"\A" + new Regex(@"\.|\$|\^|\|\[|\(|\||\)|\*|\+|\?|\\").Replace(toFind, ch => @"\" + ch).Replace('_', '.').Replace("%", ".*") + @"\z"

由此我们可以构建一个Like() 方法:

public static class MyStringExtensions

  public static bool Like(this string toSearch, string toFind)
  
    return new Regex(@"\A" + new Regex(@"\.|\$|\^|\|\[|\(|\||\)|\*|\+|\?|\\").Replace(toFind, ch => @"\" + ch).Replace('_', '.').Replace("%", ".*") + @"\z", RegexOptions.Singleline).IsMatch(toSearch);
  

因此:

bool willBeTrue = "abcdefg".Like("abcd_fg");
bool willAlsoBeTrue = "abcdefg".Like("ab%f%");
bool willBeFalse = "abcdefghi".Like("abcd_fg");

【讨论】:

不,在 SQL 中会产生错误(在 Oracle 或 PostgreSQL 等 SQL 数据库中尝试)。在 T-SQL 中,它产生 true,不是因为转义字符(这里没有涉及),而是因为字符范围说明符。如果您愿意,当然可以添加此非标准扩展。 我在 MyStringExpessions.Like() 函数中发现了这个错误。当它构建正则表达式时,它会在 [...] 前面添加反斜杠,这会破坏它。我删除了“[|”从上面的字符串,一切似乎都正常。 不幸的是,不起作用,Like("abc", "[a-z]%") 返回false @AlexZhukovskiy 正是它应该做的。 与其尝试匹配所有需要转义的字符,不如使用Regex.Escape 来代替? also documentation for \A and \z usages【参考方案2】:

有几种方法可以在 C# 中搜索为 SQL 的“LIKE”运算符。 如果只想知道字符串变量中是否存在模式,可以使用

string value = "samplevalue";
        value.Contains("eva"); // like '%eva%'
         value.StartsWith("eva");  // like 'eva%'
        value.EndsWith("eva"); // like '%eva'

如果你想从字符串列表中搜索模式,你应该使用 LINQ to Object Features。

            List<string> valuee = new List<string>  "samplevalue1", "samplevalue2", "samplevalue3" ;
        List<string> contains = (List<string>) (from val in valuee
                                        where val.Contains("pattern")
                                        select val); // like '%pattern%'

        List<string> starts = (List<string>) (from val in valuee
                                      where val.StartsWith("pattern")
                                      select val);// like 'pattern%'

        List<string> ends = (List<string>) (from val in valuee                          
                                    where val.EndsWith ("pattern")
                                    select val);// like '%pattern'

【讨论】:

【参考方案3】:

当我在合同中遇到这个问题时,除了拥有 100% 兼容的 TransactSQL LIKE 函数外,我别无选择。下面是结果——一个静态函数和一个字符串扩展方法。我确信它可以进一步优化,但它非常快并且通过了我的一长串测试场景。希望它可以帮助某人!

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<char> set = new List<char>();
            char p = '\0';

            for (int i = 0; i < str.Length; i++)
            
                char c = str[i];
                endOfPattern = (patternIndex >= pattern.Length);
                if (!endOfPattern)
                
                    p = pattern[patternIndex];

                    if (!isWildCardOn && p == '%')
                    
                        lastWildCard = patternIndex;
                        isWildCardOn = true;
                        while (patternIndex < pattern.Length &&
                            pattern[patternIndex] == '%')
                        
                            patternIndex++;
                        
                        if (patternIndex >= 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] == '-' && pattern[patternIndex + 3] == ']')
                        
                            char start = char.ToUpper(pattern[patternIndex]);
                            patternIndex += 2;
                            char end = char.ToUpper(pattern[patternIndex]);
                            if (start <= end)
                            
                                for (char ci = start; ci <= end; ci++)
                                
                                    set.Add(ci);
                                
                            
                            patternIndex++;
                        

                        while (patternIndex < pattern.Length &&
                            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 && charMatch) || (isCharSetOn && !charMatch))
                    
                        if (lastWildCard >= 0) patternIndex = lastWildCard;
                        else
                        
                            isMatch = false;
                            break;
                        
                    
                    isNotCharSetOn = isCharSetOn = false;
                
                else
                
                    if (char.ToUpper(c) == char.ToUpper(p))
                    
                        patternIndex++;
                    
                    else
                    
                        if (lastWildCard >= 0) patternIndex = lastWildCard;
                        else
                        
                            isMatch = false;
                            break;
                        
                    
                
            
            endOfPattern = (patternIndex >= pattern.Length);

            if (isMatch && !endOfPattern)
            
                bool isOnlyWildCards = true;
                for (int i = patternIndex; i < pattern.Length; i++)
                
                    if (pattern[i] != '%')
                    
                        isOnlyWildCards = false;
                        break;
                    
                
                if (isOnlyWildCards) endOfPattern = true;
            
            return isMatch && endOfPattern;
        
    

【讨论】:

比我使用的编译 RegEx 方法快 20 倍。不错! 这很好,但会破坏涉及括号的不适当模式。即"[" 的模式将抛出IndexOutOfRangeException。除了语法,它也不支持适当的范围扩展(此函数假定您将有一个范围且不涉及其他字符),文档中的 LIKE '[a-cdf]' 的情况将无法正常工作。似乎 - 需要是第一个字面处理的字符,或者可能是最后一个字符 - 文档没有指定。该文档也不清楚它如何处理愚蠢的范围,即 z-a、Z-z 等。 我认为这里还有一个非常小的逻辑错误。考虑带有文本"__" 的模式"_"。使用原样的逻辑,它会在通配符应用于第一个字符之后跳过模式部分,因为没有更多模式要分配(预期)。通常,通过将isMatch 设置为false,下划线模式会拒绝2 个字符的输入,但是将最后一个模式字符与输入字符进行比较的else if 会被命中,这意味着用于设置@ 的else 987654332@ 没有被击中。【参考方案4】:
myString.Contain("someString");  // equal with myString LIKE '%someString%'
myString.EndWith("someString");  // equal with myString LIKE '%someString'
myString.StartWith("someString");  // equal with myString LIKE 'someString%'

【讨论】:

添加一些解释,说明此答案如何帮助 OP 解决当前问题 三者的组合怎么样?我正在寻找这种模式..“不像'%/%/%/%'” 你必须使用正则表达式。【参考方案5】:

只需 .Contains() 即可为您完成工作。

"Example String".Contains("amp");   //like '%amp%'

这将返回 true,并且对其执行选择将返回所需的输出。

【讨论】:

【参考方案6】:

Operators.LikeString

https://msdn.microsoft.com/en-us/library/microsoft.visualbasic.compilerservices.operators.likestring(v=vs.100).ASPX

public static bool LikeString(
    string Source,
    string Pattern,
    CompareMethod CompareOption
)

【讨论】:

这与类似 SQL 的语法不同,但我正在寻找与类似 VB 的运算符等效的 C#。【参考方案7】:

你试过了

"This is a string".Contains("string");

【讨论】:

Contains() 并不满足所有要求。例如,@F1 LIKE ('S%T') 查询不能由 Contains() 执行【参考方案8】:

查看Regular Expressions。

【讨论】:

【参考方案9】:

可能包含

if ("bla bli blu".Contains("blu"))......

【讨论】:

【参考方案10】:

看看这个问题 - How to do SQL Like % in Linq?

此外,对于更高级的字符串模式搜索,有很多关于使用正则表达式的教程 - 例如http://www.codeproject.com/KB/dotnet/regextutorial.aspx

【讨论】:

【参考方案11】:

我认为您可以为此使用"a string.Contains("str")

它会在一个字符串中搜索一个模式,结果为真,否则为假。

【讨论】:

【参考方案12】:

作为一个迟到但正确的答案:

C-Sharp 中最接近 SQL-Like 函数的是 C# 中 SQL-Like 函数的实现。

你可以把它撕掉 http://code.google.com/p/csharp-sqlite/source/checkout [root]/csharp-sqlite/Community.CsharpSqlite/src/func_c.cs

    /*
** Implementation of the like() SQL function.  This function implements
** the build-in LIKE operator.  The first argument to the function is the
** pattern and the second argument is the string.  So, the SQL statements:
**
**       A LIKE B
**
** is implemented as like(B,A).
**
** This same function (with a different compareInfo structure) computes
** the GLOB operator.
*/
    static void likeFunc(
    sqlite3_context context,
    int argc,
    sqlite3_value[] argv
    )
    
      string zA, zB;
      u32 escape = 0;
      int nPat;
      sqlite3 db = sqlite3_context_db_handle( context );

      zB = sqlite3_value_text( argv[0] );
      zA = sqlite3_value_text( argv[1] );

      /* Limit the length of the LIKE or GLOB pattern to avoid problems
      ** of deep recursion and N*N behavior in patternCompare().
      */
      nPat = sqlite3_value_bytes( argv[0] );
      testcase( nPat == db.aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] );
      testcase( nPat == db.aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] + 1 );
      if ( nPat > db.aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] )
      
        sqlite3_result_error( context, "LIKE or GLOB pattern too complex", -1 );
        return;
      
      //Debug.Assert( zB == sqlite3_value_text( argv[0] ) );  /* Encoding did not change */

      if ( argc == 3 )
      
        /* The escape character string must consist of a single UTF-8 character.
        ** Otherwise, return an error.
        */
        string zEsc = sqlite3_value_text( argv[2] );
        if ( zEsc == null )
          return;
        if ( sqlite3Utf8CharLen( zEsc, -1 ) != 1 )
        
          sqlite3_result_error( context,
          "ESCAPE expression must be a single character", -1 );
          return;
        
        escape = sqlite3Utf8Read( zEsc, ref zEsc );
      
      if ( zA != null && zB != null )
      
        compareInfo pInfo = (compareInfo)sqlite3_user_data( context );
#if SQLITE_TEST
#if !TCLSH
        sqlite3_like_count++;
#else
        sqlite3_like_count.iValue++;
#endif
#endif
        sqlite3_result_int( context, patternCompare( zB, zA, pInfo, escape ) ? 1 : 0 );
      
    




    /*
    ** Compare two UTF-8 strings for equality where the first string can
    ** potentially be a "glob" expression.  Return true (1) if they
    ** are the same and false (0) if they are different.
    **
    ** Globbing rules:
    **
    **      '*'       Matches any sequence of zero or more characters.
    **
    **      '?'       Matches exactly one character.
    **
    **     [...]      Matches one character from the enclosed list of
    **                characters.
    **
    **     [^...]     Matches one character not in the enclosed list.
    **
    ** With the [...] and [^...] matching, a ']' character can be included
    ** in the list by making it the first character after '[' or '^'.  A
    ** range of characters can be specified using '-'.  Example:
    ** "[a-z]" matches any single lower-case letter.  To match a '-', make
    ** it the last character in the list.
    **
    ** This routine is usually quick, but can be N**2 in the worst case.
    **
    ** Hints: to match '*' or '?', put them in "[]".  Like this:
    **
    **         abc[*]xyz        Matches "abc*xyz" only
    */
    static bool patternCompare(
    string zPattern,            /* The glob pattern */
    string zString,             /* The string to compare against the glob */
    compareInfo pInfo,          /* Information about how to do the compare */
    u32 esc                     /* The escape character */
    )
    
      u32 c, c2;
      int invert;
      int seen;
      int matchOne = (int)pInfo.matchOne;
      int matchAll = (int)pInfo.matchAll;
      int matchSet = (int)pInfo.matchSet;
      bool noCase = pInfo.noCase;
      bool prevEscape = false;     /* True if the previous character was 'escape' */
      string inPattern = zPattern; //Entered Pattern

      while ( ( c = sqlite3Utf8Read( zPattern, ref zPattern ) ) != 0 )
      
        if ( !prevEscape && c == matchAll )
        
          while ( ( c = sqlite3Utf8Read( zPattern, ref zPattern ) ) == matchAll
          || c == matchOne )
          
            if ( c == matchOne && sqlite3Utf8Read( zString, ref zString ) == 0 )
            
              return false;
            
          
          if ( c == 0 )
          
            return true;
          
          else if ( c == esc )
          
            c = sqlite3Utf8Read( zPattern, ref zPattern );
            if ( c == 0 )
            
              return false;
            
          
          else if ( c == matchSet )
          
            Debug.Assert( esc == 0 );         /* This is GLOB, not LIKE */
            Debug.Assert( matchSet < 0x80 );  /* '[' is a single-byte character */
            int len = 0;
            while ( len < zString.Length && patternCompare( inPattern.Substring( inPattern.Length - zPattern.Length - 1 ), zString.Substring( len ), pInfo, esc ) == false )
            
              SQLITE_SKIP_UTF8( zString, ref len );
            
            return len < zString.Length;
          
          while ( ( c2 = sqlite3Utf8Read( zString, ref zString ) ) != 0 )
          
            if ( noCase )
            
               if( 0==((c2)&~0x7f) )
                c2 = (u32)sqlite3UpperToLower[c2]; //GlogUpperToLower(c2);
               if ( 0 == ( ( c ) & ~0x7f ) )
                 c = (u32)sqlite3UpperToLower[c]; //GlogUpperToLower(c);
              while ( c2 != 0 && c2 != c )
              
                c2 = sqlite3Utf8Read( zString, ref zString );
                if ( 0 == ( ( c2 ) & ~0x7f ) )
                  c2 = (u32)sqlite3UpperToLower[c2]; //GlogUpperToLower(c2);
              
            
            else
            
              while ( c2 != 0 && c2 != c )
              
                c2 = sqlite3Utf8Read( zString, ref zString );
              
            
            if ( c2 == 0 )
              return false;
            if ( patternCompare( zPattern, zString, pInfo, esc ) )
              return true;
          
          return false;
        
        else if ( !prevEscape && c == matchOne )
        
          if ( sqlite3Utf8Read( zString, ref zString ) == 0 )
          
            return false;
          
        
        else if ( c == matchSet )
        
          u32 prior_c = 0;
          Debug.Assert( esc == 0 );    /* This only occurs for GLOB, not LIKE */
          seen = 0;
          invert = 0;
          c = sqlite3Utf8Read( zString, ref zString );
          if ( c == 0 )
            return false;
          c2 = sqlite3Utf8Read( zPattern, ref zPattern );
          if ( c2 == '^' )
          
            invert = 1;
            c2 = sqlite3Utf8Read( zPattern, ref zPattern );
          
          if ( c2 == ']' )
          
            if ( c == ']' )
              seen = 1;
            c2 = sqlite3Utf8Read( zPattern, ref zPattern );
          
          while ( c2 != 0 && c2 != ']' )
          
            if ( c2 == '-' && zPattern[0] != ']' && zPattern[0] != 0 && prior_c > 0 )
            
              c2 = sqlite3Utf8Read( zPattern, ref zPattern );
              if ( c >= prior_c && c <= c2 )
                seen = 1;
              prior_c = 0;
            
            else
            
              if ( c == c2 )
              
                seen = 1;
              
              prior_c = c2;
            
            c2 = sqlite3Utf8Read( zPattern, ref zPattern );
          
          if ( c2 == 0 || ( seen ^ invert ) == 0 )
          
            return false;
          
        
        else if ( esc == c && !prevEscape )
        
          prevEscape = true;
        
        else
        
          c2 = sqlite3Utf8Read( zString, ref zString );
          if ( noCase )
          
            if ( c < 0x80 )
              c = (u32)sqlite3UpperToLower[c]; //GlogUpperToLower(c);
            if ( c2 < 0x80 )
              c2 = (u32)sqlite3UpperToLower[c2]; //GlogUpperToLower(c2);
          
          if ( c != c2 )
          
            return false;
          
          prevEscape = false;
        
      
      return zString.Length == 0;
    

【讨论】:

【参考方案13】:

像这样使用它:

if (lbl.Text.StartWith("hr")==true ) …

【讨论】:

好! StartWith("abc") 是 Like("abc%") 的简单等价物【参考方案14】:

这是我的实现 - 它通过了测试并成功了 - 如果您在语句中使用三个波浪号,您可能想要更改替换令牌:

private Regex LikeExpressionToRegexPattern(String likePattern)

    var replacementToken = "~~~";

    String result = likePattern.Replace("_", replacementToken)
        .Replace("%", ".*");

    result = Regex.Replace(result, @"\[.*" + replacementToken + @".*\]", "_");

    result = result.Replace(replacementToken, ".");

    return new Regex("^" + result + "$", RegexOptions.IgnoreCase);

例子:

// Define a test string.
string text = "Hello *** world";

string like = "%flow%";

// Define a regular expression and Find matches.
MatchCollection matches = LikeExpressionToRegexPattern(like).Matches(text);

//Result.
if (matches.Count > 0) 
    //Yes
 else 
    //No

【讨论】:

【参考方案15】:
public static class StringsEx

    public static IEnumerable<String> Like(this IEnumerable<String> input, String pattern)
    
        var dt = new DataTable();
        dt.Columns.Add("Search");
        foreach (String str in input)
        
            dt.Rows.Add(str);
        
        dt.DefaultView.RowFilter = String.Format("Search LIKE '0'", pattern);
        return dt.DefaultView.ToTable()
            .AsEnumerable()
            .Select(r => r.Field<String>("Search"));
    

唯一的缺点是:“字符串中间不允许使用通配符。例如,'te*xt'是不允许的。”©

【讨论】:

Like 接受两个字符串操作数并返回一个布尔结果。这没有。 数据集太糟糕了,完全不需要为此目的,加载数据集是你不想要的开销。【参考方案16】:

这里有几个很好的答案。总结一下这里已经存在的内容并且是正确的:使用 contains、startswith、endswith 是满足大多数需求的好答案。正则表达式是您想要满足更高级需求的。

不过,这些答案中没有提到的一点是,对于字符串集合,linq 可用于在调用 where 方法时应用这些过滤器。

【讨论】:

【参考方案17】:

添加一个封装VB.NET Like Operator的VB.NET DLL

【讨论】:

【参考方案18】:

正如在this answer 和this other answer 中提出的那样,Microsoft.VisualBasic.CompilerServices.Operators.LikeString 对于简单的任务来说可能是一个不错的选择,因为 RegExp 是多余的。语法不同于 RegExp 和 SQL LIKE 运算符,但它确实很容易学习(主要是因为它也很有限)。

必须添加程序集Microsoft.VisualBasic 作为对项目的引用才能使用此方法。

有关详细信息,请参阅Operators.LikeString Method,有关语法说明,请参阅Like Operator (Visual Basic)。

可以作为String类的扩展方法:

/// <summary>
/// Visual Basic like operator. Performs simple, case insensitive, string pattern matching.
/// </summary>
/// <param name="thisString"></param>
/// <param name="pattern"> ? = Any single character. * = Zero or more characters. # = Any single digit (0–9)</param>
/// <returns>true if the string matches the pattern</returns>
public static bool Like(this string thisString, string pattern)
    => Microsoft.VisualBasic.CompilerServices.Operators
        .LikeString(thisString, pattern, Microsoft.VisualBasic.CompareMethod.Text);

【讨论】:

【参考方案19】:
public static bool Like(this string value, string pattern)

    if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(pattern))
        return false;

    bool valid = true;
    string[] words = pattern.Split("*");
    int counter = words.Count();

    for (int i = 0; i < counter; i++)
    
        valid = valid && value.StartsWith(words[i]);                
        value = value.Substring(words[i].Length);
    
    return valid;
 

【讨论】:

以上是关于C# 版本的 SQL LIKE的主要内容,如果未能解决你的问题,请参考以下文章

C#中 SQL语句 带参数的like 查询怎么写

C# 构造参数查询 SQL - LIKE %

SQL Server参数化SQL语句中的like和in查询的语法(C#)

SQL Server参数化SQL语句中的like和in查询的语法(C#)

SQL Server参数化SQL语句中的like和in查询的语法(C#)

SQL C# 使用 LIKE 和通配符生成 SQL 语句;在“bla”附近给出不正确的语法