Преглед изворни кода

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
Alexandre Alapetite пре 1 година
родитељ
комит
3b15f8a5c9

+ 7 - 7
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(:#!-]|^)(?<![\\\\])/.+?(?<!\\\\)/[im]*%',
+	public static function escapeLiteralParentheses(string $input): string {
+		return preg_replace_callback('%(?<=[\\s(:#!-]|^)(?<![\\\\])(?P<delim>[\'"/]).+?(?<!\\\\)(?P=delim)[im]*%',
 			fn(array $matches): string => 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);
 	}
 

+ 1 - 1
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);

+ 1 - 1
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
 

+ 1 - 1
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
 

+ 1 - 1
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)%'],
 			],