Summary#
Text.Like(s, pattern) tests a string against a wildcard pattern. It is the deliberate opposite of
Contains, StartsWith, EndsWith: there the argument is data, here it is a pattern.
Signature#
Text.Like(<string>, <string>) -> boolDescription#
The pattern#
| in the pattern | matches |
|---|---|
% | any run of characters, including none |
_ | exactly one character |
\% \_ \\ | a literal %, _ or \ |
| anything else | itself |
Text.Like(code, "RUSH-%") // begins with RUSH-
Text.Like(code, "%-2026") // ends with -2026
Text.Like(code, "A_-%") // A, then any one character, then "-", then anything
Text.Like(label, @"50\% off") // a LITERAL percent signWhy it is not a method on the string#
s.Contains(x), s.StartsWith(x) and s.EndsWith(x) are literal searches — a % in the argument is a percent
sign. Text.Like is the wildcard one. They are spelled differently on purpose: the difference between "find this text"
and "find things shaped like this" should be visible where you read the call, not something you have to remember. C#
has no Like at all, and EF Core makes the same split for the same reason (EF.Functions.Like, never a method on
string).
It is case-sensitive#
Text.Like("ACME Ltd", "acme%") is false. To ignore case, lower both sides:
Text.Like(c.Name.ToLower(), "acme%")Inside a query, it can use an index#
This is the practical reason it exists. Contains becomes a substring search that has to look at every row; a Like
whose pattern is anchored at the front ("RUSH-%") can be answered from a btree index on the column. A pattern that
starts with % cannot — it has nothing to seek to — so prefer an anchored pattern when the table is large.
A pattern that ends with a bare \#
A trailing escape character escapes nothing, so such a pattern can never match anything. When the pattern is written
out in the source it is a compile error; double it (\\) if you meant a literal backslash.
One answer, wherever it runs#
The same call gives the same result in a browser action, in a function body on the server, and compiled into SQL — the
three implementations are tested against each other over a corpus that includes %, _, \, newlines and characters
outside the Basic Multilingual Plane.
Examples#
entity Product { string Code; string Name; }
List<Product> RushCodes() {
return Product.Where(p => Text.Like(p.Code, "RUSH-%")).ToList(); // anchored: an index can serve it
}
bool LooksLikeABatch(string code) {
return Text.Like(code, "B__-____"); // B, two characters, a dash, four characters
}
bool MentionsAPercentage(string label) {
return Text.Like(label, @"%\%%"); // contains a literal percent sign
}See also#
- Contains, StartsWith, EndsWith —
Contains/StartsWith/EndsWith, the LITERAL searches - Regex — full regular expressions, in memory only (no query form)
- execution side — why this runs in the browser too