From 3b15f8a5c9c919235c34518d14d09b41cfb93884 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 5 Dec 2024 16:19:57 +0100 Subject: Parentheses in quoted search (#7055) * Parentheses in quoted search Allow parentheses in quoted search like `author:"Bob (Team1)"` Related to https://github.com/FreshRSS/FreshRSS/pull/7054 * Doc --- app/Models/BooleanSearch.php | 14 +++++++------- app/Models/Search.php | 2 +- docs/en/users/10_filter.md | 2 +- docs/fr/users/03_Main_view.md | 2 +- tests/app/Models/SearchTest.php | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/Models/BooleanSearch.php b/app/Models/BooleanSearch.php index 375705036..529bcd338 100644 --- a/app/Models/BooleanSearch.php +++ b/app/Models/BooleanSearch.php @@ -39,7 +39,7 @@ class FreshRSS_BooleanSearch implements \Stringable { $this->raw_input = $input; if ($level === 0) { - $input = self::escapeRegexParentheses($input); + $input = self::escapeLiteralParentheses($input); $input = $this->parseUserQueryNames($input, $allowUserQueries); $input = $this->parseUserQueryIds($input, $allowUserQueries); $input = trim($input); @@ -83,7 +83,7 @@ class FreshRSS_BooleanSearch implements \Stringable { if (!empty($queries[$name])) { $fromS[] = $matches[0][$i]; if ($allowUserQueries) { - $toS[] = '(' . self::escapeRegexParentheses($queries[$name]) . ')'; + $toS[] = '(' . self::escapeLiteralParentheses($queries[$name]) . ')'; } else { $toS[] = ''; } @@ -124,7 +124,7 @@ class FreshRSS_BooleanSearch implements \Stringable { if (!empty($queries[$id])) { $fromS[] = $matches[0][$i]; if ($allowUserQueries) { - $toS[] = '(' . self::escapeRegexParentheses($queries[$id]) . ')'; + $toS[] = '(' . self::escapeLiteralParentheses($queries[$id]) . ')'; } else { $toS[] = ''; } @@ -138,16 +138,16 @@ class FreshRSS_BooleanSearch implements \Stringable { } /** - * Temporarily escape parentheses used in regex expressions. + * Temporarily escape parentheses used in regex expressions or inside quoted strings. */ - public static function escapeRegexParentheses(string $input): string { - return preg_replace_callback('%(?<=[\\s(:#!-]|^)(?[\'"/]).+?(? str_replace(['(', ')'], ['\\u0028', '\\u0029'], $matches[0]), $input ) ?? ''; } - public static function unescapeRegexParentheses(string $input): string { + public static function unescapeLiteralParentheses(string $input): string { return str_replace(['\\u0028', '\\u0029'], ['(', ')'], $input); } diff --git a/app/Models/Search.php b/app/Models/Search.php index 4a006c2d0..a887ec2f7 100644 --- a/app/Models/Search.php +++ b/app/Models/Search.php @@ -94,7 +94,7 @@ class FreshRSS_Search implements \Stringable { public function __construct(string $input) { $input = self::cleanSearch($input); $input = self::unescape($input); - $input = FreshRSS_BooleanSearch::unescapeRegexParentheses($input); + $input = FreshRSS_BooleanSearch::unescapeLiteralParentheses($input); $this->raw_input = $input; $input = $this->parseNotEntryIds($input); diff --git a/docs/en/users/10_filter.md b/docs/en/users/10_filter.md index 0aa9ed018..0aecfbaa0 100644 --- a/docs/en/users/10_filter.md +++ b/docs/en/users/10_filter.md @@ -116,7 +116,7 @@ Finally, parentheses may be used to express more complex queries, with basic neg * `(author:Alice intitle:hello) !(author:Bob intitle:world)` * `!(S:1 OR S:2)` -> ℹ️ If you need to search for a parenthesis, it needs to be escaped like `\(` or `\)` +> ℹ️ If you need to search for a parenthesis, it needs to be escaped like `\(` or `\)` or used inside a quoted string like `"a (b)"` ### Regex diff --git a/docs/fr/users/03_Main_view.md b/docs/fr/users/03_Main_view.md index 8274d0b79..e1be4ca3d 100644 --- a/docs/fr/users/03_Main_view.md +++ b/docs/fr/users/03_Main_view.md @@ -275,7 +275,7 @@ Enfin, les parenthèses peuvent être utilisées pour des expressions plus compl * `(author:Alice intitle:bonjour) !(author:Bob intitle:monde)` * `!(S:1 OR S:2)` -> ℹ️ Si vous devez chercher une parenthèse, elle doit être *échappée* comme suit : `\(` ou `\)` +> ℹ️ Si vous devez chercher une parenthèse, elle doit être *échappée* comme suit : `\(` ou `\)`, ou bien être au sein d’une chaîne de texte entre guillemets comme `"a (b)"` #### Regex diff --git a/tests/app/Models/SearchTest.php b/tests/app/Models/SearchTest.php index 7c03d5aed..04da65d3a 100644 --- a/tests/app/Models/SearchTest.php +++ b/tests/app/Models/SearchTest.php @@ -370,7 +370,7 @@ class SearchTest extends PHPUnit\Framework\TestCase { ['%Alice%', '%hello%', '%Bob%', '%world%'], ], [ - 'intitle:"\\(test\\)"', + 'intitle:"(test)"', '(e.title LIKE ? )', ['%(test)%'], ], -- cgit v1.2.3