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

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

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

【问题讨论】:

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

标签: c# .net sql string


【解决方案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】:

      【讨论】:

        【解决方案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 stackoverflow 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 answerthis 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;
                         }
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2015-04-14
                          • 2018-05-15
                          • 1970-01-01
                          • 2011-06-13
                          • 2023-03-11
                          • 2013-06-04
                          • 2011-10-03
                          相关资源
                          最近更新 更多