Contains仅支持精确子串匹配,不支持模糊、通配符或相似度匹配;区分大小写;适用于固定文本连续出现的场景,模糊需求应改用正则、Levenshtein或专用库。

Contains 方法只能做子串匹配,不是模糊匹配
Contains 是 string 类型的实例方法,它只判断一个字符串是否**完整出现**在另一字符串中,不支持通配符、正则、相似度或错位匹配。比如 "hello".Contains("ell") 返回 true,但 "hello".Contains("hllo") 或 "hello".Contains("h l l o") 都是 false——它不跳过字符,也不容忍缺失/替换。
常见错误现象:用户把“搜索包含关键词”理解为“大致像就行”,结果输入带空格、大小写混杂、或少打字母时匹配失败,却以为是 Contains 有 bug。
- 使用场景仅限于「确定某段固定文本是否作为连续子序列存在」,例如日志行里找
"ERROR"、配置值中检查是否含"dev" - 区分大小写:默认敏感,
"Hello".Contains("hello")是false;如需忽略,得用IndexOf(..., StringComparison.OrdinalIgnoreCase) >= 0 - 性能上很轻量,O(n) 时间,无额外分配,适合高频简单判断
真要模糊匹配,得换工具——Levenshtein 距离或正则
如果目标是“拼写近似”(比如用户输错 "recieve" 想匹配 "receive")或“模式通配”(比如 "a*c" 匹配 "abc"、"axxxc"),Contains 完全无能为力。
常用替代方案:
- 正则表达式:
Regex.IsMatch(input, @"a.*c")支持通配和简单模式,但不处理编辑距离 - Levenshtein 距离算法:计算两字符串最少多少次插入/删除/替换能变成一样;可封装成
IsSimilar(string a, string b, int maxDistance = 2) - 第三方库如
FuzzySharp(NuGet 可装),提供Fuzz.PartialRatio等语义级匹配,但引入依赖且有运行时开销
注意:正则在 .NET 中默认不编译缓存,高频调用建议用 RegexOptions.Compiled 或静态 Regex 实例;Levenshtein 手写要注意避免重复分配临时数组。
Contains 在 LINQ 查询中容易误用
当对 IEnumerable 调用 .Where(s => s.Contains(keyword)),看起来没问题,但如果数据源是 EF Core 的 DbSet,就可能出问题:
- EF Core 6+ 能将部分
Contains翻译成 SQL 的LIKE '%...%',但仅限于常量参数;若keyword是变量且来自闭包,可能触发客户端求值(Client Evaluation),导致整张表拉到内存再过滤 - SQL Server 的
LIKE不区分大小写(取决于排序规则),而 C# 的Contains区分,行为不一致 - 更安全的写法是显式用
EF.Functions.Like或EF.Functions.ILike(PostgreSQL)控制 SQL 行为
示例:context.Users.Where(u => EF.Functions.Like(u.Name, $"%{keyword}%")) 明确走数据库 LIKE,避免意外拖慢查询。
别把 Contains 当搜索入口,先想清楚匹配语义
很多需求表面是“模糊”,实际是「前缀匹配」「后缀匹配」「单词边界匹配」或「多词任意顺序匹配」——这些都不该硬塞给 Contains。
- 前缀:用
StartsWith,数据库对应LIKE 'xxx%' - 后缀:用
EndsWith,对应LIKE '%xxx' - 单词边界:正则
\bword\b,或拆词后用Split+Any,但注意中文无空格分词需另处理 - 多词 AND 匹配:
keywords.All(k => s.Contains(k));OR 匹配:keywords.Any(k => s.Contains(k))
最常被忽略的是:用户输入的“模糊”往往隐含业务规则,比如“姓名搜拼音首字母”“地址按行政区划层级匹配”——这时候直接套字符串函数反而掩盖了真实逻辑。











