From 456da93465e8477e62660726606e0e373f6041b5 Mon Sep 17 00:00:00 2001
From: RickyRister <42636155+RickyRister@users.noreply.github.com>
Date: Thu, 12 Jun 2025 16:30:43 -0700
Subject: [PATCH] Support regex in card search (#5971)
---
cockatrice/resources/help/search.md | 5 +++
cockatrice/src/game/filters/filter_string.cpp | 37 +++++++++++++------
2 files changed, 31 insertions(+), 11 deletions(-)
diff --git a/cockatrice/resources/help/search.md b/cockatrice/resources/help/search.md
index 917f9482e..7d707b0d1 100644
--- a/cockatrice/resources/help/search.md
+++ b/cockatrice/resources/help/search.md
@@ -58,4 +58,9 @@ In this list of examples below, each entry has an explanation and can be clicked
Grouping:
t:angel -(angel or c:w) (Any angel that doesn't have angel in its name and isn't white)
+Regular Expression:
+[/^fell/](#/^fell/) (Any card name that begins with "fell")
+[o:/counter target .* spell/](#o:/counter target .* spell/) (Any card text with "counter target *something* spell")
+[o:/for each .* and\/or .*/](#o:/for each .* and\/or .*/) (/'s can be escaped with a \)
+
diff --git a/cockatrice/src/game/filters/filter_string.cpp b/cockatrice/src/game/filters/filter_string.cpp
index e99805541..f5e9d69e9 100644
--- a/cockatrice/src/game/filters/filter_string.cpp
+++ b/cockatrice/src/game/filters/filter_string.cpp
@@ -4,6 +4,7 @@
#include
#include
+#include
#include
#include
@@ -20,7 +21,7 @@ QueryPart <- NotQuery / SetQuery / RarityQuery / CMCQuery / FormatQuery / PowerQ
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
SetQuery <- ('e'/'set') [:] FlexStringValue
-OracleQuery <- 'o' [:] RegexString
+OracleQuery <- 'o' [:] MatcherString
CMCQuery <- ('cmc'/'mv') ws? NumericExpression
@@ -42,7 +43,7 @@ ColorEx <- Color / [mc]
ColorQuery <- [cC] 'olor'? <[iI]?> <[:!]> ColorEx*
-FieldQuery <- String [:] RegexString / String ws? NumericExpression
+FieldQuery <- String [:] MatcherString / String ws? NumericExpression
NonDoubleQuoteUnlessEscaped <- '\\\"'. / !["].
NonSingleQuoteUnlessEscaped <- "\\\'". / !['].
@@ -52,8 +53,14 @@ String <- SingleApostropheString / UnescapedStringListPart+ / ["] StringMatcher {
+ search["NormalMatcher"] = [](const peg::SemanticValues &sv) -> StringMatcher {
auto target = std::any_cast(sv[0]);
- return [=](const QString &s) {
- auto sanitizedTarget = QString(target);
- sanitizedTarget.replace("\\\"", "\"");
- sanitizedTarget.replace("\\'", "'");
- return s.contains(sanitizedTarget, Qt::CaseInsensitive);
- };
+ auto sanitizedTarget = QString(target);
+ sanitizedTarget.replace("\\\"", "\"");
+ sanitizedTarget.replace("\\'", "'");
+ return [=](const QString &s) { return s.contains(sanitizedTarget, Qt::CaseInsensitive); };
+ };
+
+ search["RegexMatcher"] = [](const peg::SemanticValues &sv) -> StringMatcher {
+ auto target = std::any_cast(sv[0]);
+ auto regex = QRegularExpression(target, QRegularExpression::CaseInsensitiveOption);
+ return [=](const QString &s) { return regex.match(s).hasMatch(); };
+ };
+
+ search["RegexMatcherString"] = [](const peg::SemanticValues &sv) -> QString {
+ return QString::fromStdString(sv.token_to_string());
};
search["OracleQuery"] = [](const peg::SemanticValues &sv) -> Filter {