diff --git a/src/components/base/base-search-box.tsx b/src/components/base/base-search-box.tsx index 850510e95..079c3f739 100644 --- a/src/components/base/base-search-box.tsx +++ b/src/components/base/base-search-box.tsx @@ -34,11 +34,6 @@ const StyledTextField = styled(TextField)(({ theme }) => ({ }, })); -// 转义正则表达式特殊字符的函数 -const escapeRegExp = (string: string) => { - return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); -}; - export const BaseSearchBox = (props: SearchProps) => { const { t } = useTranslation(); const inputRef = useRef(null); @@ -60,9 +55,28 @@ export const BaseSearchBox = (props: SearchProps) => { inheritViewBox: true, }; + // 验证正则表达式的辅助函数 + const validateRegex = (pattern: string) => { + if (!pattern) return true; + try { + new RegExp(pattern); + return true; + } catch (e) { + return false; + } + }; + const createMatcher = useMemo(() => { return (searchText: string) => { try { + // 当启用正则表达式验证是否合规 + if (useRegularExpression && searchText) { + const isValid = validateRegex(searchText); + if (!isValid) { + throw new Error(t("Invalid regular expression")); + } + } + return (content: string) => { if (!searchText) return true; @@ -70,29 +84,25 @@ export const BaseSearchBox = (props: SearchProps) => { let searchItem = !matchCase ? searchText.toLowerCase() : searchText; if (useRegularExpression) { - const pattern = matchWholeWord - ? `\\b${escapeRegExp(searchItem)}\\b` - : escapeRegExp(searchItem); - return new RegExp(pattern).test(item); + return new RegExp(searchItem).test(item); } if (matchWholeWord) { - return new RegExp(`\\b${escapeRegExp(searchItem)}\\b`).test(item); + return new RegExp(`\\b${searchItem}\\b`).test(item); } return item.includes(searchItem); }; } catch (err) { - setErrorMessage(`${err}`); - return () => true; + setErrorMessage(err instanceof Error ? err.message : `${err}`); + return () => false; // 无效正则规则 不匹配值 } }; - }, [matchCase, matchWholeWord, useRegularExpression]); + }, [matchCase, matchWholeWord, useRegularExpression, t]); useEffect(() => { if (!inputRef.current) return; const value = inputRef.current.value; - setErrorMessage(""); props.onSearch(createMatcher(value), { text: value, matchCase, @@ -104,6 +114,15 @@ export const BaseSearchBox = (props: SearchProps) => { const onChange = (e: ChangeEvent) => { const value = e.target?.value ?? ""; setErrorMessage(""); + + // 验证正则表达式 + if (useRegularExpression && value) { + const isValid = validateRegex(value); + if (!isValid) { + setErrorMessage(t("Invalid regular expression")); + } + } + props.onSearch(createMatcher(value), { text: value, matchCase, @@ -113,7 +132,7 @@ export const BaseSearchBox = (props: SearchProps) => { }; return ( - + { placeholder={props.placeholder ?? t("Filter conditions")} sx={{ input: { py: 0.65, px: 1.25 } }} onChange={onChange} + error={!!errorMessage} slotProps={{ input: { sx: { pr: 1 }, diff --git a/src/locales/en.json b/src/locales/en.json index 544c14fed..4449ce15a 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -647,5 +647,6 @@ "Allowed Origins": "Allowed Origins", "Please enter a valid url": "Please enter a valid url", "Add": "Add", - "Development mode: Automatically includes Tauri and localhost origins": "Development mode: Automatically includes Tauri and localhost origins" + "Development mode: Automatically includes Tauri and localhost origins": "Development mode: Automatically includes Tauri and localhost origins", + "Invalid regular expression": "Invalid regular expression" } diff --git a/src/locales/zh.json b/src/locales/zh.json index 00ce9b5bd..cd6f290ce 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -647,5 +647,6 @@ "Allowed Origins": "允许的来源", "Please enter a valid url": "请输入有效的网址", "Add": "添加", - "Development mode: Automatically includes Tauri and localhost origins": "开发模式:自动包含 Tauri 和 localhost 来源" + "Development mode: Automatically includes Tauri and localhost origins": "开发模式:自动包含 Tauri 和 localhost 来源", + "Invalid regular expression": "无效的正则表达式" }