From d52b89ee3fb16e877359ff1a9322454a59fb77ba Mon Sep 17 00:00:00 2001 From: Joshua Laymon Date: Wed, 13 Aug 2025 15:02:10 +0000 Subject: [PATCH] Update web/core/utils.py --- web/core/utils.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/web/core/utils.py b/web/core/utils.py index c33409e..a14face 100644 --- a/web/core/utils.py +++ b/web/core/utils.py @@ -7,7 +7,56 @@ from typing import Dict, Any from django.db import transaction from core.models import Entry +# --- Search helpers restored ------------------------------------------------- +from typing import List +def terms(q: str) -> List[str]: + """ + Split a query string into search terms. + - Quoted phrases are kept together: `"good shepherd"` + - Unquoted text splits on whitespace. + - Empty/whitespace-only input returns []. + """ + if not q: + return [] + # capture "quoted phrases" OR bare tokens + rx = re.compile(r'"([^"]+)"|(\S+)') + out = [] + for m in rx.finditer(q): + phrase = m.group(1) if m.group(1) is not None else m.group(2) + t = (phrase or "").strip() + if t: + out.append(t) + return out + +def has_wildcards(s: str) -> bool: + """ + True if user supplied * or ? wildcards (FileMaker-style). + We also treat SQL wildcards % and _ as wildcards if present. + """ + if not s: + return False + return any(ch in s for ch in ("*", "?", "%", "_")) + +def wildcard_to_regex(s: str) -> str: + """ + Convert * and ? to a case-insensitive regex fragment suitable for Django's iregex. + - Escapes regex meta first, then replaces \* -> .* and \? -> . + - Wraps with '.*' so it matches anywhere (like icontains). + Example: 'lov* you?' -> '(?i).*lov.* you..*' + (The view should use iregex so (?i) or case-insensitive flag applies.) + """ + if s is None: + s = "" + # Escape regex specials, then un-escape our wildcards into regex + pat = re.escape(s) + pat = pat.replace(r"\*", ".*").replace(r"\?", ".") + # Match anywhere by default + pat = f".*{pat}.*" + # collapse consecutive ".*.*" + pat = re.sub(r"(?:\.\*){2,}", ".*", pat) + return pat +# ----------------------------------------------------------------------------- # ============================== # Helpers # ==============================