有没有办法在C#中搜索字符串中的模式?
像Sql LIKE这样的东西会非常有用。
答案 0 :(得分:50)
正则表达式允许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");
答案 1 :(得分:26)
有几种方法可以在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'
答案 2 :(得分:13)
当我在合同中遇到这个问题时,除了拥有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;
}
}
}
答案 3 :(得分:9)
SeekBar
myString.Contain("someString"); // equal with myString LIKE '%someString%'
myString.EndWith("someString"); // equal with myString LIKE '%someString'
答案 4 :(得分:5)
简单.Contains()会为你完成工作。
"Example String".Contains("amp"); //like '%amp%'
这将返回true,对其执行选择将返回所需的输出。
答案 5 :(得分:4)
包含可能
if ("bla bli blu".Contains("blu")){......}
答案 6 :(得分:3)
Operators.LikeString
public static bool LikeString(
string Source,
string Pattern,
CompareMethod CompareOption
)
答案 7 :(得分:2)
查看此问题 - How to do SQL Like % in Linq?
此外,对于更高级的字符串模式搜索,有很多关于使用正则表达式的教程 - 例如http://www.codeproject.com/KB/dotnet/regextutorial.aspx
答案 8 :(得分:2)
像这样使用:
if (lbl.Text.StartWith("hr")==true ) {…}
答案 9 :(得分:1)
我认为您可以使用"a string.Contains("str")
。
它将在字符串中搜索到patern,结果为true,如果不是,则为false。
答案 10 :(得分:1)
答案 11 :(得分:1)
答案 12 :(得分:1)
试过了吗
"This is a string".Contains("string");
答案 13 :(得分:1)
作为一个迟到但正确的答案:
C-Sharp中与SQL-Like函数最接近的是在C#中实现类似SQL的函数。
你可以把它撕掉
http://code.google.com/p/csharp-sqlite/source/checkout
[根] /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;
}
答案 14 :(得分:0)
正如this answer和this other answer <avalon:DockingManager x:Name="DockManager"
Grid.Row="2"
BorderBrush="Black"
Margin="3"
Background="#FFFDFDFD"
BorderThickness="0"
AllowMixedOrientation="True"
DocumentsSource="{Binding Documents}"
AnchorablesSource="{Binding Anchorables}">
中提出的那样,对于简单的任务来说,这可能是一个很好的选择,当RegExp过度使用时。语法与RegExp和SQL LIKE运算符不同,但它的学习非常简单(主要是因为它也非常有限)。
必须添加程序集ViewGroup
作为项目的参考才能使用此方法。
有关详细信息,请参阅Operators.LikeString Method,有关语法的说明,请参阅Like Operator (Visual Basic)。
它可以用作String类的扩展方法:
Microsoft.VisualBasic.CompilerServices.Operators.LikeString
答案 15 :(得分:0)
这是我的实现 - 它通过了测试并完成了诀窍 - 如果您在语句中使用了三个代号,则可能需要更改替换令牌:
// Looking for something similar to:
Vec<T>::init(n : usize, generator : F) -> Vec<T>
where F: Fn(usize) -> T {
// ...
}
示例:
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);
}
答案 16 :(得分:0)
这里有几个好的答案。总结已经存在的内容并纠正:使用contains,startswith,endswith是大多数需求的好答案。正则表达式是您想要的更高级需求。
但是,这些答案中没有提到的是,对于字符串集合,linq可用于在调用where方法时应用这些过滤器。答案 17 :(得分:0)
答案 18 :(得分:0)
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'。”©
答案 19 :(得分:-1)
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;
}