Parcourir la source

主打一个听劝,正则表达式工具恢复到老版

zxlie il y a 3 mois
Parent
commit
81e942e5b8
6 fichiers modifiés avec 2831 ajouts et 826 suppressions
  1. 233 115
      apps/background/background.js
  2. 4 0
      apps/json-format/index.css
  3. 1 1
      apps/json-format/index.html
  4. 854 148
      apps/regexp/index.css
  5. 84 132
      apps/regexp/index.html
  6. 1655 430
      apps/regexp/index.js

+ 233 - 115
apps/background/background.js

@@ -457,155 +457,101 @@ let BgPageInstance = (function () {
             // 任何事件,都可以通过这个钩子来完成
             else if (request.type === MSG_TYPE.DYNAMIC_ANY_THING) {
                 switch(request.thing){
+                    // 插件选项保存成功提示
                     case 'save-options':
                         notifyText({
                             message: '配置修改已生效,请继续使用!',
                             autoClose: 2000
                         });
                         break;
+                    // 触发网页截图功能
                     case 'trigger-screenshot':
-                        // 处理从popup触发的截图请求
-                        if (request.tabId) {
-                            _triggerScreenshotTool(request.tabId);
-                        } else {
-                            chrome.DynamicToolRunner({
-                                tool: 'screenshot',
-                                noPage: true
-                            });
-                        }
-                        // 记录工具使用
-                        Statistics.recordToolUsage('screenshot');
+                        handleTriggerScreenshot(request.tabId);
                         break;
+                    // 获取JSON格式化工具的配置选项
                     case 'request-jsonformat-options':
-                        Awesome.StorageMgr.get(request.params).then(result => {
-                            Object.keys(result).forEach(key => {
-                                if (['MAX_JSON_KEYS_NUMBER', 'JSON_FORMAT_THEME'].includes(key)) {
-                                    result[key] = parseInt(result[key]);
-                                } else {
-                                    result[key] = (""+result[key] !== 'false');
-                                }
-                            });
-                            callback && callback(result);
-                        });
+                        requestJsonformatOptions(request.params, callback);
                         return true; // 这个返回true是非常重要的!!!要不然callback会拿不到结果
+                    // 保存JSON格式化工具的配置选项
                     case 'save-jsonformat-options':
-                        Awesome.StorageMgr.set(request.params).then(() => {
-                            callback && callback();
-                        });
-                        // 记录工具使用
-                        Statistics.recordToolUsage('save-jsonformat-options');
+                        saveJsonformatOptions(request.params, callback);
                         return true;
+                    // 切换JSON格式化工具栏显示状态
                     case 'toggle-jsonformat-options':
-                        Awesome.StorageMgr.get('JSON_TOOL_BAR_ALWAYS_SHOW').then(result => {
-                            let show = result !== false;
-                            Awesome.StorageMgr.set('JSON_TOOL_BAR_ALWAYS_SHOW',!show).then(() => {
-                                callback && callback(!show);
-                            });
-                        });
-                        // 记录工具使用
-                        Statistics.recordToolUsage('json-format');
+                        toggleJsonformatOptions(callback);
                         return true; // 这个返回true是非常重要的!!!要不然callback会拿不到结果
+                    // 代码美化功能
                     case 'code-beautify':
                         _codeBeautify(request.params);
                         break;
+                    // 关闭代码美化功能
                     case 'close-beautify':
-                        Awesome.StorageMgr.set('JS_CSS_PAGE_BEAUTIFY',0);
-                        // 记录工具使用
-                        Statistics.recordToolUsage('code-beautify-close');
+                        handleCloseBeautify();
                         break;
+                    // 二维码解码功能
                     case 'qr-decode':
-                        chrome.DynamicToolRunner({
-                            withContent: request.params.uri,
-                            tool: 'qr-code',
-                            query: `mode=decode`
-                        });
-                        // 记录工具使用
-                        Statistics.recordToolUsage('qr-code');
+                        handleQrDecode(request.params.uri);
                         break;
+                    // 请求页面内容数据
                     case 'request-page-content':
-                        request.params = FeJson[request.tabId];
-                        delete FeJson[request.tabId];
+                        handleRequestPageContent(request);
                         break;
+                    // 设置页面性能时序数据
                     case 'set-page-timing-data':
-                        chrome.DynamicToolRunner({
-                            tool: 'page-timing',
-                            withContent: request.wpoInfo
-                        });
-                        // 记录工具使用
-                        Statistics.recordToolUsage('page-timing');
+                        handleSetPageTimingData(request.wpoInfo);
                         break;
+                    // 颜色拾取器截图功能
                     case 'color-picker-capture':
                         _colorPickerCapture(request.params);
                         // 记录工具使用
                         Statistics.recordToolUsage('color-picker');
                         break;
+                    // 分页截图功能
                     case 'add-screen-shot-by-pages':
                         _addScreenShotByPages(request.params,callback);
                         // 记录工具使用
                         Statistics.recordToolUsage('screenshot');
                         return true;
+                    // 页面截图完成处理
                     case 'page-screenshot-done':
                         _showScreenShotResult(request.params);
                         break;
+                    // 启动页面脚本注入(油猴功能)
                     case 'request-monkey-start':
                         Monkey.start(request.params);
                         break;
+                    // 注入内容脚本CSS样式
                     case 'inject-content-css':
                         _injectContentCss(sender.tab.id,request.tool,!!request.devTool);
                         break;
+                    // 打开插件选项页面
                     case 'open-options-page':
                         chrome.runtime.openOptionsPage();
                         break;
+                    // 打开打赏弹窗
                     case 'open-donate-modal':
                         chrome.gotoDonateModal(request.params.toolName);
                         break;
+                    // 加载本地脚本文件
                     case 'load-local-script':
-                        // 处理加载JSON格式化相关脚本的请求
-                        fetch(request.script)
-                            .then(response => response.text())
-                            .then(scriptContent => {
-                                callback && callback(scriptContent);
-                            })
-                            .catch(error => {
-                                console.error('加载脚本失败:', error);
-                                callback && callback(null);
-                            });
+                        loadLocalScript(request.script, callback);
                         return true; // 异步响应需要返回true
+                    // 工具使用统计埋点
                     case 'statistics-tool-usage':
                         // 埋点:自动触发json-format-auto
                         Statistics.recordToolUsage(request.params.tool_name,request.params);
                         break;
+                    // 获取热修复脚本
                     case 'fetch-hotfix-json':
-                        // 代理请求 hotfix.json,解决CORS问题
-                        fetch('https://baidufe.com/fehelper/static/js/hotfix.json?v=' + Date.now())
-                            .then(response => response.text())
-                            .then(scriptContent => {
-                                callback && callback({ success: true, content: scriptContent });
-                            })
-                            .catch(error => {
-                                callback && callback({ success: false, error: error.message });
-                            });
+                        fetchHotfixJson(callback);
                         return true; // 异步响应必须返回true
+                    // 获取插件补丁数据
                     case 'fetch-fehelper-patchs':
-                        let version = String(chrome.runtime.getManifest().version).split('.').map(n => parseInt(n)).join('.');
-                        fetch(`https://www.baidufe.com/fehelper-old/fh-patchs/v${version}.json?t=${Date.now()}`)
-                            .then(resp => resp.json())
-                            .then(data => {
-                                const patchs = data.patchs || data;
-                                chrome.storage.local.set({ FH_PATCH_HOTFIX: patchs }, () => {
-                                    callback && callback({ success: true });
-                                });
-                            })
-                            .catch(e => {
-                                callback && callback({ success: false, error: e.message });
-                            });
+                        fetchFehelperPatchs(callback);
                         return true;
+                    // 获取指定工具的补丁
                     case 'fh-get-tool-patch':
-                        if (request.toolName) {
-                            getToolPatch(request.toolName).then(patch => {
-                                callback && callback(patch);
-                            });
-                        }
+                        getToolPatch(request.toolName, callback);
                         return true;
                 }
                 callback && callback(request.params);
@@ -684,33 +630,27 @@ let BgPageInstance = (function () {
      * 初始化
      */
     let _init = function () {
+        console.log(`[FeHelper] Background初始化开始 - ${new Date().toLocaleString()}`);
+        console.log(`[FeHelper] 扩展版本: ${chrome.runtime.getManifest().version}`);
+        console.log(`[FeHelper] Service Worker启动原因: ${chrome.runtime.getContexts ? 'Context API可用' : '传统模式'}`);
+        
         _checkUpdate();
         _addExtensionListener();
         
-        // 添加截图工具直接命令 - 通过右键菜单触发
-        chrome.contextMenus.onClicked.addListener((info, tab) => {
-            if (info.menuItemId === 'fehelper-screenshot-page') {
-                _triggerScreenshotTool(tab.id);
-                // 记录工具使用
-                Statistics.recordToolUsage('screenshot');
-            }
-        });
-        
-        // 创建截图工具右键菜单
-        chrome.contextMenus.create({
-            id: 'fehelper-screenshot-page',
-            title: '网页截图',
-            contexts: ['page']
-        });
-        
         // 初始化统计功能
         Statistics.init();
         
         Menu.rebuild();
+
+        // 每天自动检查热更新(添加频率控制)
+        checkAndFetchPatchs();
+        
         // 定期清理冗余的垃圾
         setTimeout(() => {
             Awesome.gcLocalFiles();
         }, 1000 * 10);
+        
+        console.log(`[FeHelper] Background初始化完成 - ${new Date().toLocaleString()}`);
     };
 
     /**
@@ -739,19 +679,198 @@ let BgPageInstance = (function () {
         }
     });
 
-    // 获取指定工具的补丁(css/js),返回Promise
-    function getToolPatch(toolName) {
-        return new Promise(resolve => {
-            chrome.storage.local.get('FH_PATCH_HOTFIX', result => {
-                const patchs = result.FH_PATCH_HOTFIX;
-                if (patchs && patchs[toolName]) {
-                    const { css, js } = patchs[toolName];
-                    resolve({ css, js });
+    // 处理从popup触发的截图请求
+    function handleTriggerScreenshot(tabId) {
+        if (tabId) {
+            _triggerScreenshotTool(tabId);
+        } else {
+            chrome.DynamicToolRunner({
+                tool: 'screenshot',
+                noPage: true
+            });
+        }
+        // 记录工具使用
+        Statistics.recordToolUsage('screenshot');
+    }
+
+    // 请求JSON格式化选项配置
+    function requestJsonformatOptions(params, callback) {
+        Awesome.StorageMgr.get(params).then(result => {
+            Object.keys(result).forEach(key => {
+                if (['MAX_JSON_KEYS_NUMBER', 'JSON_FORMAT_THEME'].includes(key)) {
+                    result[key] = parseInt(result[key]);
                 } else {
-                    resolve({ css: '', js: '' });
+                    result[key] = (""+result[key] !== 'false');
                 }
             });
+            callback && callback(result);
+        });
+    }
+
+    // 保存JSON格式化选项配置
+    function saveJsonformatOptions(params, callback) {
+        Awesome.StorageMgr.set(params).then(() => {
+            callback && callback();
+        });
+        // 记录工具使用
+        Statistics.recordToolUsage('save-jsonformat-options');
+    }
+
+    // 切换JSON格式化选项显示状态
+    function toggleJsonformatOptions(callback) {
+        Awesome.StorageMgr.get('JSON_TOOL_BAR_ALWAYS_SHOW').then(result => {
+            let show = result !== false;
+            Awesome.StorageMgr.set('JSON_TOOL_BAR_ALWAYS_SHOW',!show).then(() => {
+                callback && callback(!show);
+            });
         });
+        // 记录工具使用
+        Statistics.recordToolUsage('json-format');
+    }
+
+    // 关闭代码美化功能
+    function handleCloseBeautify() {
+        Awesome.StorageMgr.set('JS_CSS_PAGE_BEAUTIFY',0);
+        // 记录工具使用
+        Statistics.recordToolUsage('code-beautify-close');
+    }
+
+    // 处理二维码解码
+    function handleQrDecode(uri) {
+        chrome.DynamicToolRunner({
+            withContent: uri,
+            tool: 'qr-code',
+            query: `mode=decode`
+        });
+        // 记录工具使用
+        Statistics.recordToolUsage('qr-code');
+    }
+
+    // 处理页面内容请求
+    function handleRequestPageContent(request) {
+        request.params = FeJson[request.tabId];
+        delete FeJson[request.tabId];
+    }
+
+    // 处理页面性能数据设置
+    function handleSetPageTimingData(wpoInfo) {
+        chrome.DynamicToolRunner({
+            tool: 'page-timing',
+            withContent: wpoInfo
+        });
+        // 记录工具使用
+        Statistics.recordToolUsage('page-timing');
+    }
+
+    // 获取指定工具的补丁(css/js)
+    function getToolPatch(toolName, callback) {
+        // 如果没有提供toolName,直接返回空补丁
+        if (!toolName) {
+            callback && callback({ css: '', js: '' });
+            return;
+        }
+
+        chrome.storage.local.get('FH_PATCH_HOTFIX', result => {
+            const patchs = result.FH_PATCH_HOTFIX;
+            if (patchs && patchs[toolName]) {
+                const { css, js } = patchs[toolName];
+                callback && callback({ css, js });
+            } else {
+                callback && callback({ css: '', js: '' });
+            }
+        });
+    }
+
+    // 加载本地脚本,处理加载JSON格式化相关脚本的请求
+    function loadLocalScript(scriptUrl, callback) {
+        fetch(scriptUrl)
+            .then(response => response.text())
+            .then(scriptContent => {
+                callback && callback(scriptContent);
+            })
+            .catch(error => {
+                console.error('加载脚本失败:', error);
+                callback && callback(null);
+            });
+    }
+
+    // 获取热修复脚本,代理请求 hotfix.json,解决CORS问题
+    function fetchHotfixJson(callback) {
+        fetch('https://baidufe.com/fehelper/static/js/hotfix.json?v=' + Date.now())
+            .then(response => response.text())
+            .then(scriptContent => {
+                callback && callback({ success: true, content: scriptContent });
+            })
+            .catch(error => {
+                callback && callback({ success: false, error: error.message });
+            });
+    }
+
+    // 检查并获取补丁(带频率控制)
+    function checkAndFetchPatchs() {
+        const PATCH_CHECK_INTERVAL = 5 * 60 * 1000; // 5min
+        const STORAGE_KEY = 'FH_LAST_PATCH_CHECK';
+        
+        chrome.storage.local.get(STORAGE_KEY, (result) => {
+            const lastCheck = result[STORAGE_KEY] || 0;
+            const now = Date.now();
+            
+            if (now - lastCheck > PATCH_CHECK_INTERVAL) {
+                console.log(`[FeHelper] 距离上次检查已超过5min,开始检查热更新...`);
+                
+                fetchFehelperPatchs((result) => {
+                    if (result && result.success) {
+                        console.log(`[FeHelper] 自动热更新成功,版本: v${result.version}`);
+                    } else if (result && result.notFound) {
+                        console.log(`[FeHelper] 当前版本暂无热更新补丁`);
+                    } else {
+                        console.log(`[FeHelper] 自动热更新检查失败:`, result?.error);
+                    }
+                    
+                    // 更新最后检查时间
+                    chrome.storage.local.set({ [STORAGE_KEY]: now });
+                });
+            } else {
+                const nextCheck = new Date(lastCheck + PATCH_CHECK_INTERVAL);
+                console.log(`[FeHelper] 距离上次检查不足5min,下次检查时间: ${nextCheck.toLocaleString()}`);
+            }
+        });
+    }
+
+    // 获取FeHelper热修复补丁
+    function fetchFehelperPatchs(callback) {
+        let version = String(chrome.runtime.getManifest().version).split('.').map(n => parseInt(n)).join('.');
+        let patchUrl = `https://www.baidufe.com/fehelper-old/fh-patchs/v${version}.json`;
+        
+        // 先检测文件是否存在(使用HEAD请求)
+        fetch(patchUrl, { method: 'HEAD' })
+            .then(response => {
+                if (response.ok) {
+                    // 文件存在,进行正常的fetch操作
+                    return fetch(`${patchUrl}?t=${Date.now()}`)
+                        .then(resp => {
+                            if (!resp.ok) {
+                                throw new Error(`HTTP ${resp.status}: ${resp.statusText}`);
+                            }
+                            return resp.json();
+                        })
+                        .then(data => {
+                            const patchs = data.patchs || data;
+                            chrome.storage.local.set({ FH_PATCH_HOTFIX: patchs }, () => {
+                                console.log(`[FeHelper] 成功获取版本 v${version} 的热修复补丁`);
+                                callback && callback({ success: true, version });
+                            });
+                        });
+                } else {
+                    // 文件不存在
+                    console.log(`[FeHelper] 服务器上不存在版本 v${version} 的补丁文件`);
+                    callback && callback({ success: false, error: '补丁文件不存在', notFound: true });
+                }
+            })
+            .catch(e => {
+                console.error(`[FeHelper] 获取补丁失败:`, e);
+                callback && callback({ success: false, error: e.message });
+            });
     }
 
     return {
@@ -760,5 +879,4 @@ let BgPageInstance = (function () {
     };
 })();
 
-BgPageInstance.init();
-
+BgPageInstance.init();

+ 4 - 0
apps/json-format/index.css

@@ -11,6 +11,10 @@ html,body {
     height:100%;
 }
 
+.v-cloak{
+    display: none;
+}
+
 .wp-json {
     width:auto;
 }

+ 1 - 1
apps/json-format/index.html

@@ -129,7 +129,7 @@
             </div>
     
             <!-- JSONPath示例模态框 -->
-            <div id="jsonPathExamplesModal" class="jsonpath-modal" v-show="showJsonPathExamplesModal" @click="closeJsonPathExamplesModal">
+            <div id="jsonPathExamplesModal" class="jsonpath-modal v-cloak" v-show="showJsonPathExamplesModal" @click="closeJsonPathExamplesModal">
                 <div class="jsonpath-modal-content" @click.stop>
                     <div class="jsonpath-modal-header">
                         <h3>JSONPath查询示例</h3>

+ 854 - 148
apps/regexp/index.css

@@ -1,3 +1,6 @@
+/* 导入Bootstrap样式 */
+@import url("../static/css/bootstrap.min.css");
+
 /* 全局样式 */
 * {
     margin: 0;
@@ -7,78 +10,117 @@
 
 body {
     font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
-    background-color: #f5f6fa;
-    color: #2c3e50;
+    background: #fff !important;
+    color: #333 !important;
     line-height: 1.4;
 }
 
-/* 头部样式 */
-.header {
+/* Panel样式 */
+.panel {
+    margin-bottom: 20px;
     background-color: #fff;
-    padding: 0.8rem 1.5rem;
-    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
-    position: sticky;
-    top: 0;
-    z-index: 100;
+    border: 1px solid transparent;
+    border-radius: 4px;
+    -webkit-box-shadow: 0 1px 1px rgba(0,0,0,.05);
+    box-shadow: 0 1px 1px rgba(0,0,0,.05);
 }
 
-.logo {
-    display: flex;
-    align-items: center;
-    gap: 0.8rem;
+.panel-default {
+    border-color: #ddd;
 }
 
-.logo h1 {
-    font-size: 1.2rem;
-    margin: 0;
+.panel-heading {
+    padding: 10px 15px;
+    border-bottom: 1px solid transparent;
+    border-top-left-radius: 3px;
+    border-top-right-radius: 3px;
+    color: #333;
+    background-color: #f5f5f5;
+    border-color: #ddd;
 }
 
-.subtitle {
-    color: #3498db;
-    font-size: 0.9rem;
-    margin-left: 0.5rem;
-    padding: 0.2rem 0.5rem;
-    background-color: rgba(52, 152, 219, 0.1);
-    border-radius: 4px;
+.panel-title {
+    margin-top: 0;
+    margin-bottom: 0;
+    font-size: 16px;
+    color: inherit;
+}
+
+.x-a-high {
+    color: #337ab7;
+    text-decoration: none;
+}
+
+.x-a-high:hover {
+    color: #23527c;
+    text-decoration: underline;
+}
+
+.nav-icon {
+    margin-right: 3px;
 }
 
 /* 主容器样式 */
 .container {
     max-width: 1200px;
-    margin: 0.5rem auto;
-    padding: 0 0.5rem;
-}
-
-/* 正则分类样式 */
-.regex-categories {
-    column-count: 3;
-    column-gap: 0.5rem;
     margin: 0 auto;
+    padding: 20px;
+    background-color: #fff;
 }
 
-.category {
+/* 新版正则分类区域美化 */
+.category-section {
     background: #fff;
-    border-radius: 8px;
-    padding: 0.8rem;
-    box-shadow: 0 1px 3px rgba(0,0,0,0.1);
-    break-inside: avoid;
-    margin-bottom: 0.5rem;
-    page-break-inside: avoid;
-    -webkit-column-break-inside: avoid;
+    border-radius: 10px;
+    box-shadow: 0 2px 8px rgba(0,0,0,0.04);
+    margin-bottom: 24px;
+    padding: 18px 24px 12px 24px;
 }
 
-.category h2 {
-    font-size: 1rem;
-    color: #2c3e50;
-    margin-bottom: 0.5rem;
-    padding-bottom: 0.3rem;
-    border-bottom: 2px solid #3498db;
+.category-title {
+    font-size: 18px;
+    font-weight: bold;
+    color: #333;
+    margin-bottom: 14px;
+    letter-spacing: 1px;
 }
 
-.regex-list {
-    display: grid;
-    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
-    gap: 0.5rem;
+.category-btn-group {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 12px 16px;
+}
+
+.regex-item {
+    background: #f7f8fa;
+    border: 1px solid #e3e6eb;
+    border-radius: 6px;
+    padding: 8px 18px;
+    font-size: 15px;
+    color: #1976d2;
+    cursor: pointer;
+    margin-bottom: 8px;
+    transition: background 0.2s, box-shadow 0.2s, color 0.2s;
+    outline: none;
+}
+.regex-item:hover, .regex-item:focus {
+    background: #e3f2fd;
+    color: #0d47a1;
+    box-shadow: 0 2px 8px rgba(25, 118, 210, 0.08);
+    border-color: #90caf9;
+}
+
+@media (max-width: 600px) {
+    .category-section {
+        padding: 12px 8px 8px 8px;
+    }
+    .category-title {
+        font-size: 16px;
+    }
+    .regex-item {
+        font-size: 13px;
+        padding: 6px 10px;
+    }
 }
 
 /* 正则项目和工具提示样式 */
@@ -297,8 +339,7 @@ pre {
 
 .search-box {
     position: relative;
-    width: 60%;
-    max-width: 600px;
+    width: 90%;
 }
 
 .search-box input {
@@ -364,101 +405,6 @@ pre {
 
 
 
-/* 工具市场按钮样式(保持不变) */
-.panel-title>a.x-other-tools {
-    margin: 1px 0 0;
-    font-size: 13px;
-    cursor: pointer;
-    text-decoration: none;
-    -webkit-user-select: none;
-    user-select: none;
-    color: #333;
-    float: right;
-    background-color: #f5f8ff;
-    padding: 5px 10px;
-    border-radius: 15px;
-    border: 1px solid #d0d9ff;
-    transition: all 0.3s ease;
-    display: flex;
-    align-items: center;
-    position: absolute;
-    right: 15px;
-    top: 8px;
-}
-
-.panel-title>a.x-other-tools .icon-plus-circle {
-    display: inline-block;
-    width: 16px;
-    height: 16px;
-    background: url(../static/img/plus-circle.svg) no-repeat center center;
-    background-size: contain;
-    margin-right: 5px;
-}
-
-.panel-title>a.x-other-tools .tool-market-badge {
-    display: inline-block;
-    background-color: #4d89fe;
-    color: white;
-    padding: 2px 6px;
-    border-radius: 10px;
-    margin-left: 5px;
-    font-size: 12px;
-    font-weight: bold;
-}
-
-.panel-title>a.x-other-tools:hover {
-    color: #333;
-    background-color: #e6edff;
-    box-shadow: 0 2px 5px rgba(0,0,0,0.15);
-    transform: translateY(-1px);
-}
-
-
-/* 保持原有的顶部导航样式 */
-.x-donate-link {
-    float: right;
-    line-height: 18px;
-    color: #2563eb;
-    cursor: pointer;
-    text-decoration: none;
-    border: none;
-    white-space: nowrap;
-    margin-right: auto;
-    border-radius: 20px;
-    background-color: #eff6ff;
-    transition: all 0.2s ease;
-    position: relative;
-    display: inline-flex;
-    align-items: center;
-    box-shadow: 0 1px 2px rgba(37, 99, 235, 0.1);
-    position: absolute;
-    right: 230px;
-    top: 12px;
-    padding: 4px 12px;
-    margin: 0 10px;
-    font-size: 12px;
-    font-weight: normal;
-}
-
-.x-donate-link:hover {
-    background-color: #dbeafe;
-    color: #1d4ed8;
-    text-decoration: none;
-    box-shadow: 0 2px 4px rgba(37, 99, 235, 0.15);
-    transform: translateY(-1px);
-}
-
-.x-donate-link>a {
-    font-size: 12px;
-    color: blue;
-    cursor: pointer;
-    text-decoration: underline;
-}
-.x-donate-link>a:hover {
-    text-decoration: underline;
-    color: #f00;
-}
-
 /* 正则可视化调试区域样式 */
 .regex-visual-debugger {
     background: #fff;
@@ -500,7 +446,6 @@ pre {
     border-radius: 4px;
     padding: 0.6rem 0.8rem;
     margin-bottom: 0.5rem;
-    background: #f8f9fa;
     resize: vertical;
     transition: border-color 0.2s;
 }
@@ -508,6 +453,10 @@ pre {
     border-color: #2563eb;
     background: #fff;
 }
+.match-position {
+    color: #888;
+    font-size: 12px;
+}
 .visual-debugger-actions {
     display: flex;
     align-items: center;
@@ -542,7 +491,6 @@ pre {
     color: #222;
     margin-top: 0.2rem;
     word-break: break-all;
-    white-space: pre-wrap;
 }
 .visual-result .visual-match {
     background: #fff3cd;
@@ -619,3 +567,761 @@ pre {
     font-size: 0.92em;
     margin-left: 0.5rem;
 }
+
+/* 基础样式 */
+* {
+    box-sizing: border-box;
+}
+
+body {
+    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+    margin: 0;
+    padding: 0;
+    background-color: #f8f9fa;
+    color: #333;
+    line-height: 1.6;
+}
+
+/* 头部样式 */
+.header {
+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+    color: white;
+    padding: 20px 0;
+    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
+}
+
+.logo {
+    display: flex;
+    align-items: center;
+    max-width: 1200px;
+    margin: 0 auto;
+    padding: 0 20px;
+    gap: 12px;
+}
+
+.logo h3 {
+    margin: 0;
+    font-size: 24px;
+    font-weight: 600;
+}
+
+.logo .subtitle {
+    color: rgba(255, 255, 255, 0.9);
+    font-size: 14px;
+    margin-left: auto;
+}
+
+
+
+.tool-market-badge {
+    background: #ff6b6b;
+    color: white;
+    padding: 2px 8px;
+    border-radius: 10px;
+    font-size: 12px;
+    margin-left: 5px;
+}
+
+/* 容器样式 */
+.container {
+    max-width: 1200px;
+    margin: 0 auto;
+    padding: 20px;
+}
+
+/* Tab切换样式 */
+.tab-container {
+    background: white;
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    margin-bottom: 20px;
+}
+
+.tab-header {
+    display: flex;
+    background: #f5f5f5;
+    border-bottom: 1px solid #ddd;
+    border-top-left-radius: 3px;
+    border-top-right-radius: 3px;
+}
+
+.tab-btn {
+    flex: 1;
+    padding: 12px 16px;
+    border: none;
+    background: transparent;
+    cursor: pointer;
+    font-size: 14px;
+    color: #666;
+    transition: all 0.2s ease;
+    position: relative;
+}
+
+.tab-btn:hover {
+    background: #e6e6e6;
+    color: #337ab7;
+}
+
+.tab-btn.active {
+    background: #fff !important;
+    color: #337ab7 !important;
+    border-bottom: 2px solid #337ab7 !important;
+}
+
+.tab-content {
+    display: none;
+    padding: 20px;
+    min-height: 500px;
+    background: #fff;
+}
+
+.tab-content.active {
+    display: block;
+}
+
+/* 正则可视化调试区域 */
+.regex-visual-debugger {
+    background: #f8f9fa;
+    border-radius: 8px;
+    padding: 20px;
+    margin-bottom: 30px;
+    border: 1px solid #e9ecef;
+}
+
+.regex-visual-debugger h2 {
+    margin-top: 0;
+    color: #495057;
+    font-size: 20px;
+    margin-bottom: 20px;
+}
+
+.visual-debugger-form {
+    display: flex;
+    gap: 10px;
+    margin-bottom: 15px;
+    flex-wrap: wrap;
+    align-items: center;
+}
+
+.visual-debugger-form select,
+.visual-debugger-form input[type="text"] {
+    padding: 8px 12px;
+    border: 1px solid #ced4da;
+    border-radius: 4px;
+    font-size: 14px;
+}
+
+.visual-debugger-form select {
+    min-width: 200px;
+}
+
+.visual-debugger-form input[type="text"] {
+    flex: 1;
+    min-width: 300px;
+}
+
+.visual-flags-group {
+    display: flex;
+    gap: 10px;
+    align-items: center;
+}
+
+.flag-btn {
+    display: flex;
+    align-items: center;
+    gap: 5px;
+    padding: 5px 10px;
+    border: 1px solid #ced4da;
+    border-radius: 4px;
+    background: white;
+    cursor: pointer;
+    font-size: 14px;
+    transition: all 0.3s ease;
+}
+
+.flag-btn:hover {
+    background: #f8f9fa;
+}
+
+.flag-btn input[type="checkbox"] {
+    margin: 0;
+}
+
+.flag-desc {
+    font-size: 12px;
+    color: #6c757d;
+    margin-left: 10px;
+}
+
+.visual-debugger-form textarea {
+    width: 100%;
+    padding: 10px;
+    border: 1px solid #ced4da;
+    border-radius: 4px;
+    font-family: 'Courier New', monospace;
+    font-size: 14px;
+    resize: vertical;
+}
+
+.visual-debugger-actions {
+    display: flex;
+    gap: 10px;
+    align-items: center;
+    margin-bottom: 15px;
+}
+
+.visual-debugger-actions button {
+    padding: 8px 16px;
+    background: #667eea;
+    color: white;
+    border: none;
+    border-radius: 4px;
+    cursor: pointer;
+    font-size: 14px;
+    transition: background 0.3s ease;
+}
+
+.visual-debugger-actions button:hover {
+    background: #5a6fd8;
+}
+
+.visual-error-msg {
+    color: #dc3545;
+    font-size: 14px;
+}
+
+.visual-result {
+    background: white;
+    border: 1px solid #e9ecef;
+    border-radius: 4px;
+    padding: 15px;
+    min-height: 100px;
+}
+
+/* 搜索框样式 */
+.search-container {
+    margin-bottom: 30px;
+}
+
+.search-box {
+    position: relative;
+    max-width: 1200px;
+    margin: 0 auto;
+}
+
+.search-box input {
+    width: 100%;
+    padding: 12px 40px 12px 16px;
+    border: 2px solid #e9ecef;
+    border-radius: 25px;
+    font-size: 16px;
+    transition: border-color 0.3s ease;
+}
+
+.search-box input:focus {
+    outline: none;
+    border-color: #667eea;
+}
+
+.search-icon {
+    position: absolute;
+    right: 15px;
+    top: 50%;
+    transform: translateY(-50%);
+    font-size: 18px;
+    color: #6c757d;
+}
+
+/* 正则表达式分类样式 */
+.regex-categories {
+    display: grid;
+    gap: 30px;
+}
+
+.category {
+    background: white;
+    border-radius: 8px;
+    padding: 20px;
+    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
+}
+
+.category h2 {
+    margin-top: 0;
+    color: #495057;
+    font-size: 18px;
+    margin-bottom: 15px;
+    padding-bottom: 10px;
+    border-bottom: 2px solid #e9ecef;
+}
+
+.regex-list {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+    gap: 10px;
+}
+
+.regex-item {
+    padding: 12px 16px;
+    background: #f8f9fa;
+    border: 1px solid #e9ecef;
+    border-radius: 6px;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    font-size: 14px;
+    text-align: center;
+}
+
+.regex-item:hover {
+    background: #667eea;
+    color: white;
+    transform: translateY(-2px);
+    box-shadow: 0 4px 8px rgba(102, 126, 234, 0.3);
+}
+
+/* 模态框样式 */
+.modal {
+    display: none;
+    position: fixed;
+    z-index: 1000;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0,0,0,0.5);
+}
+
+.modal-content {
+    background-color: white;
+    margin: 5% auto;
+    padding: 20px;
+    border-radius: 8px;
+    width: 90%;
+    max-width: 800px;
+    max-height: 80vh;
+    overflow-y: auto;
+    position: relative;
+}
+
+.close {
+    position: absolute;
+    right: 20px;
+    top: 15px;
+    font-size: 28px;
+    font-weight: bold;
+    cursor: pointer;
+    color: #aaa;
+}
+
+.close:hover {
+    color: #000;
+}
+
+.regex-versions {
+    display: grid;
+    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+    gap: 20px;
+    margin-bottom: 20px;
+}
+
+.version {
+    background: #f8f9fa;
+    padding: 15px;
+    border-radius: 6px;
+    border: 1px solid #e9ecef;
+}
+
+.version h3 {
+    margin-top: 0;
+    color: #495057;
+    font-size: 16px;
+    margin-bottom: 10px;
+}
+
+.version pre {
+    background: #2d3748;
+    color: #e2e8f0;
+    padding: 10px;
+    border-radius: 4px;
+    font-size: 13px;
+    overflow-x: auto;
+    margin-bottom: 10px;
+}
+
+.copy-btn {
+    background: #667eea;
+    color: white;
+    border: none;
+    padding: 6px 12px;
+    border-radius: 4px;
+    cursor: pointer;
+    font-size: 12px;
+    transition: background 0.3s ease;
+}
+
+.copy-btn:hover {
+    background: #5a6fd8;
+}
+
+.regex-description {
+    background: #f8f9fa;
+    padding: 15px;
+    border-radius: 6px;
+    border-left: 4px solid #667eea;
+}
+
+.regex-description h3 {
+    margin-top: 0;
+    color: #495057;
+    font-size: 16px;
+    margin-bottom: 10px;
+}
+
+/* 旧版样式 - 开始 */
+html {
+    font-size: 14px;
+}
+
+.pannel-select {
+    position: absolute;
+    right: 0;
+    top: 0;
+    width: 255px;
+    height: 30px;
+}
+
+.reglist_select {
+    padding: 0 0;
+    height: 24px;
+}
+
+.reg_link {
+    display: inline-block;
+    float: right;
+    text-align: right;
+    font-size: 12px;
+    margin-top: 4px;
+}
+
+.reg_pre {
+    border: none;
+    background: transparent;
+}
+
+.reg_reg_input {
+    resize: none;
+}
+
+.reg_textarea {
+    padding: 0;
+    width: 100%;
+    resize: none;
+    font: 100% "courier new", monospace;
+}
+
+#srcWrapper {
+    padding: 12px;
+}
+
+.wrapper #srcBackground {
+    padding: 0;
+}
+
+.mod-regexp {
+    margin: 0 auto;
+    padding: 0;
+    background: #FFF;
+}
+
+#srcWrapper {
+    background: #fff;
+    border: 1px solid #ccc;
+    min-height: 50px;
+    position: relative;
+    border-radius: 4px;
+    -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
+    box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
+    -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
+    -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
+    transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
+}
+
+#srcBackground {
+    padding: 4px;
+    margin: 0;
+    position: absolute;
+    z-index: 1;
+    width: 100%;
+    word-break: break-all;
+    line-height: 14px;
+}
+
+#srcBackground i, #srcBackground b {
+    font: 100% "courier new", monospace;
+    font-style: normal;
+    font-weight: normal;
+    font-size: 14px;
+    margin: 0;
+    padding: 0;
+    background: #fff;
+    color: #fff;
+}
+
+#srcBackground b {
+    background: #dd0;
+    color: #dd0;
+}
+
+#srcCode {
+    background: transparent;
+    margin: 0;
+    border: none;
+    font-size: 14px;
+    position: relative;
+    z-index: 2;
+    outline: none;
+    overflow-y: hidden;
+}
+
+#rstCount {
+    color: #f00;
+}
+
+#rstCode {
+    padding: 3px;
+}
+
+#regTip {
+    font-size: 12px;
+    color: #d00;
+    display: none;
+}
+
+.x-tip {
+    font-size: 12px;
+    color: #00b;
+}
+
+.ui-po-r {
+    position: relative;
+}
+
+.ui-mb-20 {
+    margin-bottom: 20px;
+}
+
+.ui-mt-20 {
+    margin-top: 20px;
+}
+
+.panel-subtitle {
+    font-size: 16px;
+    color: #333;
+    margin-bottom: 10px;
+}
+
+.wrapper {
+    background: white;
+    border-radius: 8px;
+}
+
+.panel-body {
+    padding: 20px;
+}
+
+.table {
+    width: 100%;
+    border-collapse: collapse;
+    margin-bottom: 20px;
+}
+
+.table th,
+.table td {
+    padding: 8px;
+    text-align: left;
+    border-bottom: 1px solid #ddd;
+}
+
+.table th {
+    background-color: #f8f9fa;
+    font-weight: 600;
+}
+
+.table-striped tbody tr:nth-child(odd) {
+    background-color: #f8f9fa;
+}
+
+.table-hover tbody tr:hover {
+    background-color: #e9ecef;
+}
+
+.table-bordered {
+    border: 1px solid #dee2e6;
+}
+
+.table-bordered th,
+.table-bordered td {
+    border: 1px solid #dee2e6;
+}
+
+.table-condensed th,
+.table-condensed td {
+    padding: 5px;
+}
+
+.active {
+    background: #fff !important;
+    color: #337ab7 !important;
+    border-color: #337ab7 !important;
+}
+
+.num {
+    width: 60px;
+    text-align: center;
+}
+
+.content {
+    word-break: break-all;
+}
+
+.index {
+    width: 120px;
+    text-align: center;
+}
+
+/* 旧版样式 - 结束 */
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+    .container {
+        padding: 10px;
+    }
+    
+    .logo {
+        flex-direction: column;
+        gap: 10px;
+        text-align: center;
+    }
+    
+    .logo .subtitle {
+        margin-left: 0;
+    }
+    
+    .visual-debugger-form {
+        flex-direction: column;
+    }
+    
+    .visual-debugger-form select,
+    .visual-debugger-form input[type="text"] {
+        width: 100%;
+        min-width: auto;
+    }
+    
+    .visual-flags-group {
+        flex-wrap: wrap;
+    }
+    
+    .regex-list {
+        grid-template-columns: 1fr;
+    }
+    
+    .regex-versions {
+        grid-template-columns: 1fr;
+    }
+    
+    .modal-content {
+        width: 95%;
+        margin: 2% auto;
+    }
+    
+    .pannel-select {
+        position: static;
+        width: 100%;
+        margin-bottom: 10px;
+    }
+    
+    .reglist_select {
+        width: 100%;
+        height: auto;
+    }
+    
+    .reg_link {
+        float: none;
+        display: block;
+        margin-top: 10px;
+    }
+}
+
+/* 隐藏类 */
+.hidden {
+    display: none !important;
+}
+
+/* 加载动画 */
+.loading {
+    display: inline-block;
+    width: 20px;
+    height: 20px;
+    border: 3px solid #f3f3f3;
+    border-top: 3px solid #667eea;
+    border-radius: 50%;
+    animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+    0% { transform: rotate(0deg); }
+    100% { transform: rotate(360deg); }
+}
+
+/* 成功/错误提示 */
+.success {
+    color: #28a745;
+}
+
+.error {
+    color: #dc3545;
+}
+
+/* 滚动条样式 */
+::-webkit-scrollbar {
+    width: 8px;
+    height: 8px;
+}
+
+::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 4px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+    background: #a8a8a8;
+}
+
+/* 移除所有蓝色背景色 */
+[style*="background: #1677ff"],
+[style*="background-color: #1677ff"],
+[style*="background: #1890ff"],
+[style*="background-color: #1890ff"] {
+    background: #fff !important;
+    background-color: #fff !important;
+}
+
+/* 正则输入框和文本内容输入框固定高度 */
+.visual-regex-input,
+.visual-test-text,
+#regText,
+#srcCode {
+    height: 44px;
+    min-height: 44px;
+    max-height: 200px;
+    box-sizing: border-box;
+    resize: vertical;
+    line-height: 1.6;
+}
+.r-index {
+    width: 160px;;
+}

+ 84 - 132
apps/regexp/index.html

@@ -5,149 +5,101 @@
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <title>正则表达式工具 - FeHelper</title>
         <link rel="stylesheet" href="index.css">
+        <script type="text/javascript" src="../static/vendor/jquery/jquery-3.3.1.min.js"></script>
         <script type="text/javascript" src="../static/vendor/evalCore.min.js"></script>
     </head>
     <body>
-        <header class="header">
-            <div class="logo panel-title">
-                <img src="../../static/img/fe-48.png" alt="FeHelper Logo" width="24" height="24">
-                <h3>FeHelper | 正则表达式速查</h3>
-                <span class="subtitle">支持 JavaScript / Python / PHP / Java 等语言的正则速查</span>
-                <a href="#" class="x-donate-link" id="donate-link"><i class="nav-icon">❤&nbsp;</i>打赏鼓励</a>
-                <a class="x-other-tools" id="other-tools"><i class="icon-plus-circle"></i> 探索更多实用工具 <span class="tool-market-badge">工具市场</span></a>
+        <div class="panel panel-default" style="margin-bottom: 0px;">
+            <div class="panel-heading">
+                <h3 class="panel-title">
+                    <a href="https://www.baidufe.com/fehelper/index/index.html" target="_blank" class="x-a-high">
+                        <img src="../static/img/fe-16.png" alt="fehelper"/> FeHelper</a>:正则表达式工具
+                        <a class="x-other-tools" id="btnOtherTools"><i class="icon-plus-circle"></i> 探索更多实用工具 <span class="tool-market-badge">工具市场</span></a>
+                        <span class="x-donate-link" id="donateLink"><a href="#" id="donateLink"><i class="nav-icon">❤</i>&nbsp;打赏鼓励</a></span>
+                </h3>
             </div>
-        </header>
+        </div>
 
         <main class="container">
-            
-            <!-- 正则可视化调试区域 -->
-            <section class="regex-visual-debugger">
-                <h2>正则表达式可视化调试</h2>
-                <div class="visual-debugger-form">
-                    <select id="visualRegexPreset">
-                        <option value="">自定义/选择常用正则</option>
-                        <!-- 动态插入所有内置正则 -->
-                    </select>
-                    <input type="text" id="visualRegex" placeholder="请输入正则表达式,如:^\\d{3}-\\d{8}$" />
-                    <div class="visual-flags-group">
-                        <label class="flag-btn" title="g:全局匹配(查找所有匹配项)">
-                            <input type="checkbox" value="g" /> g
-                        </label>
-                        <label class="flag-btn" title="i:忽略大小写">
-                            <input type="checkbox" value="i" /> i
-                        </label>
-                        <label class="flag-btn" title="m:多行模式(^$作用于每行)">
-                            <input type="checkbox" value="m" /> m
-                        </label>
-                        <span class="flag-desc">常用标志:g=全局 i=忽略大小写 m=多行</span>
-                    </div>
-                    <input type="text" id="visualFlags" placeholder="标志(可选,如:gim)" maxlength="5" style="display:none;" />
-                </div>
-                <textarea id="visualTestText" rows="4" placeholder="请输入要测试的文本"></textarea>
-                <div class="visual-debugger-actions">
-                    <button id="visualTestBtn">测试匹配</button>
-                    <span id="visualErrorMsg" class="visual-error-msg"></span>
-                </div>
-                <div id="visualResult" class="visual-result"></div>
-            </section>
-            
-            <div class="search-container">
-                <div class="search-box">
-                    <input type="text" id="regexSearch" placeholder="搜索正则表达式..." />
-                    <span class="search-icon">🔍</span>
+            <!-- Tab 切换区域 -->
+            <div class="tab-container">
+                <div class="tab-header">
+                    <button class="tab-btn active" data-tab="new-version">新版 - 正则速查</button>
+                    <button class="tab-btn" data-tab="old-version">旧版 - 正则测试</button>
                 </div>
-            </div>
-            
-            <div class="regex-categories">
-                <!-- 验证类 -->
-                <section class="category">
-                    <h2>验证类</h2>
-                    <div class="regex-list">
-                        <div class="regex-item" data-regex-id="email">邮箱验证</div>
-                        <div class="regex-item" data-regex-id="phone">手机号验证</div>
-                        <div class="regex-item" data-regex-id="tel">固定电话验证</div>
-                        <div class="regex-item" data-regex-id="url">URL验证</div>
-                        <div class="regex-item" data-regex-id="idcard">身份证验证</div>
-                        <div class="regex-item" data-regex-id="ipv4">IPv4地址验证</div>
-                        <div class="regex-item" data-regex-id="date">日期验证</div>
-                        <div class="regex-item" data-regex-id="number">数字验证</div>
-                        <div class="regex-item" data-regex-id="number-n-digits">n位数字验证</div>
-                        <div class="regex-item" data-regex-id="number-min-n-digits">至少n位数字验证</div>
-                        <div class="regex-item" data-regex-id="number-range-digits">数字位数范围验证</div>
-                        <div class="regex-item" data-regex-id="decimal">小数验证</div>
-                        <div class="regex-item" data-regex-id="integer">整数验证</div>
-                        <div class="regex-item" data-regex-id="chinese-name">中文姓名验证</div>
-                        <div class="regex-item" data-regex-id="english-name">英文姓名验证</div>
-                        <div class="regex-item" data-regex-id="username">用户名验证</div>
-                        <div class="regex-item" data-regex-id="password-strong">强密码验证</div>
-                        <div class="regex-item" data-regex-id="mac-address">MAC地址验证</div>
-                        <div class="regex-item" data-regex-id="hex-color">16进制颜色验证</div>
-                        <div class="regex-item" data-regex-id="version-number">版本号验证</div>
-                    </div>
-                </section>
-
-                <!-- 提取类 -->
-                <section class="category">
-                    <h2>提取类</h2>
-                    <div class="regex-list">
-                        <div class="regex-item" data-regex-id="html-tag">HTML标签提取</div>
-                        <div class="regex-item" data-regex-id="img-url">图片URL提取</div>
-                        <div class="regex-item" data-regex-id="chinese">中文字符提取</div>
-                        <div class="regex-item" data-regex-id="numbers">数字提取</div>
-                        <div class="regex-item" data-regex-id="email-extract">邮箱地址提取</div>
-                        <div class="regex-item" data-regex-id="link-extract">链接提取</div>
-                        <div class="regex-item" data-regex-id="color-hex">颜色值提取</div>
-                        <div class="regex-item" data-regex-id="ip-extract">IP地址提取</div>
+                
+                <!-- 新版内容 -->
+                <div class="tab-content active" id="new-version">
+                    <!-- 正则可视化调试区域 -->
+                    <section class="regex-visual-debugger">
+                        <h2>正则表达式可视化调试</h2>
+                        <div class="visual-debugger-form">
+                            <select id="visualRegexPreset">
+                                <option value="">自定义/选择常用正则</option>
+                                <!-- 动态插入所有内置正则 -->
+                            </select>
+                            <input type="text" id="visualRegex" placeholder="请输入正则表达式,如:^\\d{3}-\\d{8}$" />
+                            <div class="visual-flags-group">
+                                <label class="flag-btn" title="g:全局匹配(查找所有匹配项)">
+                                    <input type="checkbox" value="g" /> g
+                                </label>
+                                <label class="flag-btn" title="i:忽略大小写">
+                                    <input type="checkbox" value="i" /> i
+                                </label>
+                                <label class="flag-btn" title="m:多行模式(^$作用于每行)">
+                                    <input type="checkbox" value="m" /> m
+                                </label>
+                                <span class="flag-desc">常用标志:g=全局 i=忽略大小写 m=多行</span>
+                            </div>
+                            <input type="text" id="visualFlags" placeholder="标志(可选,如:gim)" maxlength="5" style="display:none;" />
+                        </div>
+                        <textarea id="visualTestText" rows="4" placeholder="请输入要测试的文本"></textarea>
+                        <div class="visual-debugger-actions">
+                            <button id="visualTestBtn">测试匹配</button>
+                            <span id="visualErrorMsg" class="visual-error-msg"></span>
+                        </div>
+                        <div id="visualResult" class="visual-result"></div>
+                    </section>
+                    
+                    <div class="search-container">
+                        <div class="search-box">
+                            <input type="text" id="regexSearch" placeholder="输入关键词,搜索正则表达式..." />
+                            <span class="search-icon">🔍</span>
+                        </div>
                     </div>
-                </section>
-
-                <!-- 替换类 -->
-                <section class="category">
-                    <h2>替换类</h2>
-                    <div class="regex-list">
-                        <div class="regex-item" data-regex-id="trim">去除首尾空格</div>
-                        <div class="regex-item" data-regex-id="remove-html">去除HTML标签</div>
-                        <div class="regex-item" data-regex-id="camelcase">驼峰命名转换</div>
-                        <div class="regex-item" data-regex-id="remove-script">去除Script标签</div>
-                        <div class="regex-item" data-regex-id="remove-space">去除多余空格</div>
-                        <div class="regex-item" data-regex-id="remove-comment">去除注释</div>
-                    </div>
-                </section>
-
-                <!-- 格式化类 -->
-                <section class="category">
-                    <h2>格式化类</h2>
-                    <div class="regex-list">
-                        <div class="regex-item" data-regex-id="money">金额格式化</div>
-                        <div class="regex-item" data-regex-id="phone-format">手机号格式化</div>
-                        <div class="regex-item" data-regex-id="date-format">日期格式化</div>
-                        <div class="regex-item" data-regex-id="card-format">银行卡格式化</div>
-                        <div class="regex-item" data-regex-id="idcard-format">身份证格式化</div>
-                    </div>
-                </section>
+                    
+                    <div id="regexCategoryContainer"></div>
+                </div>
 
-                <!-- 特殊字符类 -->
-                <section class="category">
-                    <h2>特殊字符类</h2>
-                    <div class="regex-list">
-                        <div class="regex-item" data-regex-id="emoji">Emoji表情</div>
-                        <div class="regex-item" data-regex-id="special-char">特殊字符</div>
-                        <div class="regex-item" data-regex-id="unicode">Unicode字符</div>
-                        <div class="regex-item" data-regex-id="invisible-char">不可见字符</div>
-                    </div>
-                </section>
+                <!-- 旧版内容 -->
+                <div class="tab-content" id="old-version">
+                    <div class="wrapper" id="pageContainer">
+                        <div class="panel-body mod-regexp">
+                            <div class="ui-po-r ui-mb-20">
+                                <h3 class="panel-subtitle">正则表达式</h3>
+                                <span class="pannel-select reg-list">
+                                    <select class="form-control reglist_select" id="regList">
+                                        <option value="">-- 常用正则表达式 --</option>
+                                    </select>
+                                </span>
+                            </div>
+                            <textarea class="reg_reg_input form-control" id="regText" placeholder="输入正则表达式,如:/[0-9A-Z].*?/igm" rows="1" tabindex="10"></textarea>
+                            <a class="reg_link" href="https://chrome.fehelper.com/blog/detail.html?id=eb10deb92f2c05ca32cf" target="_blank" tabindex="30">Javascript正则表达式语法</a>
 
-                <!-- 编程相关 -->
-                <section class="category">
-                    <h2>编程相关</h2>
-                    <div class="regex-list">
-                        <div class="regex-item" data-regex-id="variable">变量命名</div>
-                        <div class="regex-item" data-regex-id="function">函数声明</div>
-                        <div class="regex-item" data-regex-id="json">JSON格式</div>
-                        <div class="regex-item" data-regex-id="xml">XML标签</div>
-                        <div class="regex-item" data-regex-id="css">CSS选择器</div>
+                            <div id="src" class="ui-mt-20">
+                                <h3 class="panel-subtitle">文本内容</h3>
+                                <div id="srcWrapper">
+                                    <pre class="reg_pre" id="srcBackground"></pre>
+                                    <textarea class="reg_textarea" id="srcCode" placeholder="输入待匹配的文本" contenteditable="true"></textarea>
+                                </div>
+                            </div>
+                            <div id="rst" class="">
+                                <h3 class="panel-subtitle">匹配结果&nbsp;&nbsp;<span id="rstCount"></span></h3>
+                                <div id="rstCode"></div>
+                            </div>
+                        </div>
                     </div>
-                </section>
+                </div>
             </div>
         </main>
 

+ 1655 - 430
apps/regexp/index.js

@@ -3,6 +3,7 @@ const regexDatabase = {
     // 验证类
     'email': {
         title: '邮箱验证',
+        category: '验证类',
         description: '验证电子邮箱地址的合法性,支持@前的各种字符组合,@后必须是域名格式',
         patterns: {
             javascript: '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/',
@@ -13,6 +14,7 @@ const regexDatabase = {
     },
     'phone': {
         title: '手机号验证',
+        category: '验证类',
         description: '验证中国大陆手机号码,支持最新号段',
         patterns: {
             javascript: '/^1[3-9]\\d{9}$/',
@@ -23,6 +25,7 @@ const regexDatabase = {
     },
     'tel': {
         title: '固定电话验证',
+        category: '验证类',
         description: '验证固定电话号码,支持区号+号码的格式',
         patterns: {
             javascript: '/^(0\\d{2,3}-?)?\\d{7,8}$/',
@@ -33,6 +36,7 @@ const regexDatabase = {
     },
     'password': {
         title: '密码强度验证',
+        category: '验证类',
         description: '密码必须包含大小写字母、数字和特殊字符,长度8-16位',
         patterns: {
             javascript: '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$/',
@@ -43,6 +47,7 @@ const regexDatabase = {
     },
     'qq': {
         title: 'QQ号验证',
+        category: '验证类',
         description: '验证QQ号,必须是5-11位数字,首位不能为0',
         patterns: {
             javascript: '/^[1-9][0-9]{4,10}$/',
@@ -53,6 +58,7 @@ const regexDatabase = {
     },
     'postal': {
         title: '邮政编码验证',
+        category: '验证类',
         description: '验证中国邮政编码,6位数字',
         patterns: {
             javascript: '/^\\d{6}$/',
@@ -63,6 +69,7 @@ const regexDatabase = {
     },
     'account': {
         title: '账号验证',
+        category: '验证类',
         description: '验证账号,字母开头,允许5-16位,字母数字下划线组合',
         patterns: {
             javascript: '/^[a-zA-Z]\\w{4,15}$/',
@@ -73,16 +80,18 @@ const regexDatabase = {
     },
     'url': {
         title: 'URL验证',
+        category: '验证类',
         description: '验证URL地址的合法性,支持http、https协议,可选端口、路径、参数、锚点,支持localhost和IP地址',
         patterns: {
             javascript: '/^(https?:\\/\\/)?((([\\w-]+\\.)+[\\w-]+|localhost|\\d{1,3}(?:\\.\\d{1,3}){3}))(\\:\\d{1,5})?(\\/[^\\s?#]*)?(\\?[^\\s#]*)?(#[^\\s]*)?$/i',
-            python: 'r"^(https?:\/\/)?((([\w-]+\.)+[\w-]+|localhost|\d{1,3}(?:\.\d{1,3}){3}))(\:\d{1,5})?(\/[^s?#]*)?(\?[^s#]*)?(#[^s]*)?$"',
+            python: 'r"(https?:\/\/)?((([\w-]+\.)+[\w-]+|localhost|\d{1,3}(?:\.\d{1,3}){3}))(\:\d{1,5})?(\/[^s?#]*)?(\?[^s#]*)?(#[^s]*)?$"',
             php: '/^(https?:\\/\\/)?((([\\w-]+\\.)+[\\w-]+|localhost|\\d{1,3}(?:\\.\\d{1,3}){3}))(\\:\\d{1,5})?(\\/[^\\s?#]*)?(\\?[^\\s#]*)?(#[^\\s]*)?$/i',
             java: '^(https?:\\/\\/)?((([\\w-]+\\.)+[\\w-]+|localhost|\\d{1,3}(?:\\.\\d{1,3}){3}))(\\:\\d{1,5})?(\\/[^\\s?#]*)?(\\?[^\\s#]*)?(#[^\\s]*)?$'
         }
     },
     'idcard': {
         title: '身份证验证',
+        category: '验证类',
         description: '验证中国大陆居民身份证号码,支持18位',
         patterns: {
             javascript: '/^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9X]$/',
@@ -93,6 +102,7 @@ const regexDatabase = {
     },
     'ipv4': {
         title: 'IPv4地址验证',
+        category: '验证类',
         description: '验证IPv4地址格式',
         patterns: {
             javascript: '/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
@@ -103,6 +113,7 @@ const regexDatabase = {
     },
     'date': {
         title: '日期验证',
+        category: '验证类',
         description: '验证日期格式(YYYY-MM-DD)',
         patterns: {
             javascript: '/^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$/',
@@ -115,6 +126,7 @@ const regexDatabase = {
     // 提取类
     'html-tag': {
         title: 'HTML标签提取',
+        category: '提取类',
         description: '提取HTML标签及其内容',
         patterns: {
             javascript: '/<([a-z][a-z0-9]*)[^>]*>.*?<\\/\\1>/gi',
@@ -125,6 +137,7 @@ const regexDatabase = {
     },
     'img-url': {
         title: '图片URL提取',
+        category: '提取类',
         description: '提取HTML中的图片URL',
         patterns: {
             javascript: '/<img[^>]+src="([^">]+)"/gi',
@@ -135,6 +148,7 @@ const regexDatabase = {
     },
     'chinese': {
         title: '中文字符提取',
+        category: '提取类',
         description: '提取中文字符',
         patterns: {
             javascript: '/[\\u4e00-\\u9fa5]/g',
@@ -145,6 +159,7 @@ const regexDatabase = {
     },
     'numbers': {
         title: '数字提取',
+        category: '提取类',
         description: '提取字符串中的数字',
         patterns: {
             javascript: '/\\d+(\\.\\d+)?/g',
@@ -155,6 +170,7 @@ const regexDatabase = {
     },
     'email-extract': {
         title: '邮箱地址提取',
+        category: '提取类',
         description: '提取文本中的邮箱地址',
         patterns: {
             javascript: '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g',
@@ -165,6 +181,7 @@ const regexDatabase = {
     },
     'color-hex': {
         title: '颜色值提取',
+        category: '提取类',
         description: '提取16进制颜色值,支持3位和6位格式',
         patterns: {
             javascript: '/#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g',
@@ -175,6 +192,7 @@ const regexDatabase = {
     },
     'ip-extract': {
         title: 'IP地址提取',
+        category: '提取类',
         description: '提取IPv4地址',
         patterns: {
             javascript: '/\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g',
@@ -187,6 +205,7 @@ const regexDatabase = {
     // 替换类
     'trim': {
         title: '去除首尾空格',
+        category: '替换类',
         description: '去除字符串首尾的空白字符',
         patterns: {
             javascript: '/^\\s+|\\s+$/g',
@@ -197,27 +216,41 @@ const regexDatabase = {
     },
     'remove-html': {
         title: '去除HTML标签',
+        category: '替换类',
         description: '去除文本中的HTML标签',
         patterns: {
-            javascript: '/<[^>]+>/g',
-            python: 'r"<[^>]+>"',
-            php: '/<[^>]+>/',
-            java: '<[^>]+>'
+            javascript: '/<[^>]*>/g',
+            python: 'r"<[^>]*>"',
+            php: '/<[^>]*>/',
+            java: '<[^>]*>'
+        }
+    },
+    'camelcase': {
+        title: '驼峰命名转换',
+        category: '替换类',
+        description: '将下划线命名转换为驼峰命名',
+        patterns: {
+            javascript: '/_([a-z])/g',
+            python: 'r"_([a-z])"',
+            php: '/_([a-z])/',
+            java: '_([a-z])'
         }
     },
     'remove-script': {
         title: '去除Script标签',
+        category: '替换类',
         description: '去除HTML中的script标签及其内容',
         patterns: {
             javascript: '/<script[^>]*>[\\s\\S]*?<\\/script>/gi',
             python: 'r"<script[^>]*>[\\s\\S]*?</script>"',
             php: '/<script[^>]*>[\\s\\S]*?<\\/script>/i',
-            java: '<script[^>]*>[\\s\\S]*?</script>'
+            java: '<script[^>]*>[\s\S]*?</script>'
         }
     },
     'remove-space': {
         title: '去除多余空格',
-        description: '去除字符串中的多余空格,保留单个空格',
+        category: '替换类',
+        description: '将多个连续空格替换为单个空格',
         patterns: {
             javascript: '/\\s+/g',
             python: 'r"\\s+"',
@@ -227,91 +260,264 @@ const regexDatabase = {
     },
     'remove-comment': {
         title: '去除注释',
-        description: '去除代码中的单行和多行注释',
+        category: '替换类',
+        description: '去除JavaScript单行和多行注释',
         patterns: {
-            javascript: '/(\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/)/gm',
-            python: 'r"(#.*$)|(\'\'\'[\\s\\S]*?\'\'\')|(\\"\\"\\"[\\s\\S]*?\\"\\"\\"))"',
-            php: '/(\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/)/m',
-            java: '(/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/)|(//.*)'
+            javascript: '/\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*$/gm',
+            python: 'r"#.*$"',
+            php: '/\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*$/m',
+            java: '\\/\\*[\\s\\S]*?\\*\\/|\\/\\/.*$'
+        }
+    },
+    // 补全缺失项(占位符)
+    'number': {
+        title: '数字验证',
+        category: '验证类',
+        description: '验证是否为数字',
+        patterns: {
+            javascript: '/^\\d+$/',
+            python: 'r"^\\d+$"',
+            php: '/^\\d+$/',
+            java: '^\\d+$'
+        }
+    },
+    'number-n-digits': {
+        title: 'n位数字验证',
+        category: '验证类',
+        description: '验证是否为n位数字',
+        patterns: {
+            javascript: '/^\\d{n}$/',
+            python: 'r"^\\d{n}$"',
+            php: '/^\\d{n}$/',
+            java: '^\\d{n}$'
+        }
+    },
+    'number-min-n-digits': {
+        title: '至少n位数字验证',
+        category: '验证类',
+        description: '验证是否为至少n位数字',
+        patterns: {
+            javascript: '/^\\d{n,}$/',
+            python: 'r"^\\d{n,}$"',
+            php: '/^\\d{n,}$/',
+            java: '^\\d{n,}$'
+        }
+    },
+    'number-range-digits': {
+        title: '数字位数范围验证',
+        category: '验证类',
+        description: '验证数字位数范围',
+        patterns: {
+            javascript: '/^\\d{m,n}$/',
+            python: 'r"^\\d{m,n}$"',
+            php: '/^\\d{m,n}$/',
+            java: '^\\d{m,n}$'
+        }
+    },
+    'decimal': {
+        title: '小数验证',
+        category: '验证类',
+        description: '验证小数',
+        patterns: {
+            javascript: '/^\\d+\\.\\d+$/',
+            python: 'r"^\\d+\\.\\d+$"',
+            php: '/^\\d+\\.\\d+$/',
+            java: '^\\d+\\.\\d+$'
+        }
+    },
+    'integer': {
+        title: '整数验证',
+        category: '验证类',
+        description: '验证整数',
+        patterns: {
+            javascript: '/^-?\\d+$/',
+            python: 'r"^-?\\d+$"',
+            php: '/^-?\\d+$/',
+            java: '^-?\\d+$'
+        }
+    },
+    'chinese-name': {
+        title: '中文姓名验证',
+        category: '验证类',
+        description: '验证中文姓名',
+        patterns: {
+            javascript: '/^[\\u4e00-\\u9fa5]{2,}$/',
+            python: 'r"^[\\u4e00-\\u9fa5]{2,}$"',
+            php: '/^[\\x{4e00}-\\x{9fa5}]{2,}$/u',
+            java: '^[\\u4e00-\\u9fa5]{2,}$'
+        }
+    },
+    'english-name': {
+        title: '英文姓名验证',
+        category: '验证类',
+        description: '验证英文姓名',
+        patterns: {
+            javascript: '/^[A-Za-z\\s]+$/',
+            python: 'r"^[A-Za-z\\s]+$"',
+            php: '/^[A-Za-z\\s]+$/',
+            java: '^[A-Za-z\\s]+$'
+        }
+    },
+    'username': {
+        title: '用户名验证',
+        category: '验证类',
+        description: '验证用户名',
+        patterns: {
+            javascript: '/^[a-zA-Z0-9_]{4,16}$/',
+            python: 'r"^[a-zA-Z0-9_]{4,16}$"',
+            php: '/^[a-zA-Z0-9_]{4,16}$/',
+            java: '^[a-zA-Z0-9_]{4,16}$'
+        }
+    },
+    'password-strong': {
+        title: '强密码验证',
+        category: '验证类',
+        description: '强密码(8-16位,含大小写字母、数字、特殊字符)',
+        patterns: {
+            javascript: '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$/',
+            python: 'r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$"',
+            php: '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$/',
+            java: '^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$'
+        }
+    },
+    'mac-address': {
+        title: 'MAC地址验证',
+        category: '验证类',
+        description: '验证MAC地址',
+        patterns: {
+            javascript: '/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/',
+            python: 'r"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"',
+            php: '/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/',
+            java: '^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$'
+        }
+    },
+    'hex-color': {
+        title: '16进制颜色验证',
+        category: '验证类',
+        description: '验证16进制颜色',
+        patterns: {
+            javascript: '/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/',
+            python: 'r"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"',
+            php: '/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/',
+            java: '^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$'
+        }
+    },
+    'version-number': {
+        title: '版本号验证',
+        category: '验证类',
+        description: '验证版本号格式',
+        patterns: {
+            javascript: '/^\\d+\\.\\d+\\.\\d+$/',
+            python: 'r"^\\d+\\.\\d+\\.\\d+$"',
+            php: '/^\\d+\\.\\d+\\.\\d+$/',
+            java: '^\\d+\\.\\d+\\.\\d+$'
+        }
+    },
+    'link-extract': {
+        title: '链接提取',
+        category: '提取类',
+        description: '提取文本中的链接',
+        patterns: {
+            javascript: '/https?:\\/\\/[^\\s]+/g',
+            python: 'r"https?:\\/\\/[^\\s]+"',
+            php: '/https?:\\/\\/[^\\s]+/g',
+            java: 'https?:\\/\\/[^\\s]+'
         }
     },
-
     // 格式化类
     'money': {
         title: '金额格式化',
-        description: '将数字转换为金额格式(每三位加逗号)',
+        category: '格式化类',
+        description: '匹配金额(保留两位小数)',
         patterns: {
-            javascript: '/(\\d)(?=(\\d{3})+(?!\\d))/g',
-            python: 'r"(\\d)(?=(\\d{3})+(?!\\d))"',
-            php: '/(\\d)(?=(\\d{3})+(?!\\d))/',
-            java: '(\\d)(?=(\\d{3})+(?!\\d))'
+            javascript: '/^\\d+(?:\\.\\d{1,2})?$/',
+            python: 'r"^\\d+(?:\\.\\d{1,2})?$"',
+            php: '/^\\d+(?:\\.\\d{1,2})?$/',
+            java: '^\\d+(?:\\.\\d{1,2})?$'
         }
     },
     'phone-format': {
         title: '手机号格式化',
-        description: '将手机号格式化为 xxx-xxxx-xxxx',
+        category: '格式化类',
+        description: '匹配中国大陆手机号格式',
         patterns: {
-            javascript: '/(\\d{3})(\\d{4})(\\d{4})/',
-            python: 'r"(\\d{3})(\\d{4})(\\d{4})"',
-            php: '/(\\d{3})(\\d{4})(\\d{4})/',
-            java: '(\\d{3})(\\d{4})(\\d{4})'
+            javascript: '/^1[3-9]\\d{9}$/',
+            python: 'r"^1[3-9]\\d{9}$"',
+            php: '/^1[3-9]\\d{9}$/',
+            java: '^1[3-9]\\d{9}$'
         }
     },
     'date-format': {
         title: '日期格式化',
-        description: '将日期字符串格式化为指定格式',
+        category: '格式化类',
+        description: '匹配日期格式(YYYY-MM-DD)',
         patterns: {
-            javascript: '/(\\d{4})-(\\d{2})-(\\d{2})/',
-            python: 'r"(\\d{4})-(\\d{2})-(\\d{2})"',
-            php: '/(\\d{4})-(\\d{2})-(\\d{2})/',
-            java: '(\\d{4})-(\\d{2})-(\\d{2})'
+            javascript: '/^\\d{4}-\\d{2}-\\d{2}$/',
+            python: 'r"^\\d{4}-\\d{2}-\\d{2}$"',
+            php: '/^\\d{4}-\\d{2}-\\d{2}$/',
+            java: '^\\d{4}-\\d{2}-\\d{2}$'
         }
     },
     'card-format': {
         title: '银行卡格式化',
-        description: '将银行卡号每4位添加一个空格',
+        category: '格式化类',
+        description: '匹配银行卡号(16或19位数字)',
         patterns: {
-            javascript: '/(\\d{4})(?=\\d)/g',
-            python: 'r"(\\d{4})(?=\\d)"',
-            php: '/(\\d{4})(?=\\d)/',
-            java: '(\\d{4})(?=\\d)'
+            javascript: '/^\\d{16}|\\d{19}$/',
+            python: 'r"^\\d{16}|\\d{19}$"',
+            php: '/^\\d{16}|\\d{19}$/',
+            java: '^\\d{16}|\\d{19}$'
         }
     },
     'idcard-format': {
         title: '身份证格式化',
-        description: '将身份证号码按6-8-4格式分组',
+        category: '格式化类',
+        description: '匹配中国大陆18位身份证号',
         patterns: {
-            javascript: '/(^\\d{6})(\\d{8})(\\d{4})/g',
-            python: 'r"(^\\d{6})(\\d{8})(\\d{4})"',
-            php: '/(^\\d{6})(\\d{8})(\\d{4})/',
-            java: '(^\\d{6})(\\d{8})(\\d{4})'
+            javascript: '/^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$/',
+            python: 'r"^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$"',
+            php: '/^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$/',
+            java: '^[1-9]\\d{5}(19|20)\\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])\\d{3}[0-9Xx]$'
         }
     },
-
     // 特殊字符类
     'emoji': {
         title: 'Emoji表情',
-        description: '匹配Unicode emoji表情符号',
+        category: '特殊字符类',
+        description: '匹配Emoji表情字符',
         patterns: {
-            javascript: '/[\\u{1F300}-\\u{1F9FF}]/gu',
-            python: 'r"[\\U0001F300-\\U0001F9FF]"',
-            php: '/[\\x{1F300}-\\x{1F9FF}]/u',
-            java: '[\\uD83C\\uDF00-\\uD83D\\uDDFF]'
+            javascript: '/[\\uD83C-\\uDBFF\\uDC00-\\uDFFF]+/g',
+            python: 'r"[\\U0001F600-\\U0001F64F]"',
+            php: '/[\\x{1F600}-\\x{1F64F}]/u',
+            java: '[\\uD83C-\\uDBFF\\uDC00-\\uDFFF]'
         }
     },
     'special-char': {
         title: '特殊字符',
-        description: '匹配常见特殊字符',
+        category: '特殊字符类',
+        description: '匹配特殊字符',
+        patterns: {
+            javascript: '/[!@#$%^&*(),.?\":{}|<>]/g',
+            python: 'r"[!@#$%^&*(),.?\":{}|<>]"',
+            php: '/[!@#$%^&*(),.?\":{}|<>]/',
+            java: '[!@#$%^&*(),.?\":{}|<>]'
+        }
+    },
+    'unicode': {
+        title: 'Unicode字符',
+        category: '特殊字符类',
+        description: '匹配Unicode字符',
         patterns: {
-            javascript: '/[`~!@#$%^&*()_\\-+=<>?:"{}|,.\\/;\'\\[\\]·~!@#¥%……&*()——\\-+={}|《》?:""【】、;\',。、]/g',
-            python: 'r"[`~!@#$%^&*()_\\-+=<>?:\\"{}|,.\\/;\\\'\\[\\]·~!@#¥%……&*()——\\-+={}|《》?:""【】、;\\\',。、]"',
-            php: '/[`~!@#$%^&*()_\\-+=<>?:"{}|,.\\/;\'\\[\\]·~!@#¥%……&*()——\\-+={}|《》?:""【】、;\',。、]/',
-            java: '[`~!@#$%^&*()_\\-+=<>?:"{}|,.\\/;\'\\[\\]·~!@#¥%……&*()——\\-+={}|《》?:""【】、;\',。、]'
+            javascript: '/\\u[0-9a-fA-F]{4}/g',
+            python: 'r"\\u[0-9a-fA-F]{4}"',
+            php: '/\\u[0-9a-fA-F]{4}/',
+            java: '\\u[0-9a-fA-F]{4}'
         }
     },
     'invisible-char': {
         title: '不可见字符',
-        description: '匹配不可见字符(空格、制表符、换行符等)',
+        category: '特殊字符类',
+        description: '匹配不可见字符(如空格、制表符等)',
         patterns: {
             javascript: '/[\\s\\u200B-\\u200D\\uFEFF]/g',
             python: 'r"[\\s\\u200B-\\u200D\\uFEFF]"',
@@ -319,506 +525,1525 @@ const regexDatabase = {
             java: '[\\s\\u200B-\\u200D\\uFEFF]'
         }
     },
-
     // 编程相关
     'variable': {
         title: '变量命名',
-        description: '验证合法的变量名(字母、数字、下划线,字母开头)',
+        category: '编程相关',
+        description: '匹配常见变量命名(字母、下划线、数字,不能以数字开头)',
         patterns: {
-            javascript: '/^[a-zA-Z_$][a-zA-Z0-9_$]*$/',
+            javascript: '/^[a-zA-Z_][a-zA-Z0-9_]*$/',
             python: 'r"^[a-zA-Z_][a-zA-Z0-9_]*$"',
             php: '/^[a-zA-Z_][a-zA-Z0-9_]*$/',
-            java: '^[a-zA-Z_$][a-zA-Z0-9_$]*$'
+            java: '^[a-zA-Z_][a-zA-Z0-9_]*$'
         }
     },
     'function': {
         title: '函数声明',
-        description: '匹配函数声明语句',
+        category: '编程相关',
+        description: '匹配JavaScript函数声明',
         patterns: {
-            javascript: '/function\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\([^)]*\\)\\s*{/',
-            python: 'r"def\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\([^)]*\\)\\s*:"',
-            php: '/function\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\([^)]*\\)\\s*{/',
-            java: '(public|private|protected|static|\\s) +[\\w\\<\\>\\[\\]]+\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\([^)]*\\)\\s*\\{'
+            javascript: '/function\\s+[a-zA-Z_][a-zA-Z0-9_]*\\s*\\(/',
+            python: 'r"def\\s+[a-zA-Z_][a-zA-Z0-9_]*\\s*\\("',
+            php: '/function\\s+[a-zA-Z_][a-zA-Z0-9_]*\\s*\\(/',
+            java: 'function\\s+[a-zA-Z_][a-zA-Z0-9_]*\\s*\\('
         }
     },
     'json': {
         title: 'JSON格式',
-        description: '验证JSON字符串格式',
+        category: '编程相关',
+        description: '匹配简单JSON格式',
         patterns: {
-            javascript: '/^\\s*({[\\s\\S]*}|\\[[\\s\\S]*\\])\\s*$/',
-            python: 'r"^\\s*({[\\s\\S]*}|\\[[\\s\\S]*\\])\\s*$"',
-            php: '/^\\s*({[\\s\\S]*}|\\[[\\s\\S]*\\])\\s*$/',
-            java: '^\\s*({[\\s\\S]*}|\\[[\\s\\S]*\\])\\s*$'
+            javascript: '/^\\{.*\\}$/s',
+            python: 'r"^\\{.*\\}$"',
+            php: '/^\\{.*\\}$/s',
+            java: '^\\{.*\\}$'
         }
     },
     'xml': {
         title: 'XML标签',
+        category: '编程相关',
         description: '匹配XML标签',
         patterns: {
-            javascript: '/<\\/?([a-z][\\w-]*)(?:\\s+[^>]*)?>/gi',
-            python: 'r"<\\/?([a-z][\\w-]*)(?:\\s+[^>]*)?>)"',
-            php: '/<\\/?([a-z][\\w-]*)(?:\\s+[^>]*)?>/i',
-            java: '<\\/?([a-z][\\w-]*)(?:\\s+[^>]*)?>'
+            javascript: '/<([a-zA-Z][a-zA-Z0-9]*)\\b[^>]*>(.*?)<\\/\\1>/',
+            python: 'r"<([a-zA-Z][a-zA-Z0-9]*)\\b[^>]*>(.*?)<\\/\\1>"',
+            php: '/<([a-zA-Z][a-zA-Z0-9]*)\\b[^>]*>(.*?)<\\/\\1>/',
+            java: '<([a-zA-Z][a-zA-Z0-9]*)\\b[^>]*>(.*?)<\\/\\1>'
         }
     },
     'css': {
         title: 'CSS选择器',
-        description: '匹配CSS选择器',
+        category: '编程相关',
+        description: '匹配简单CSS选择器',
         patterns: {
-            javascript: '/[.#]?[a-zA-Z_-][\\w-]*(?:\\[[^\\]]+\\])?(?:\\.[a-zA-Z_-][\\w-]*)*/',
-            python: 'r"[.#]?[a-zA-Z_-][\\w-]*(?:\\[[^\\]]+\\])?(?:\\.[a-zA-Z_-][\\w-]*)*"',
-            php: '/[.#]?[a-zA-Z_-][\\w-]*(?:\\[[^\\]]+\\])?(?:\\.[a-zA-Z_-][\\w-]*)*/',
-            java: '[.#]?[a-zA-Z_-][\\w-]*(?:\\[[^\\]]+\\])?(?:\\.[a-zA-Z_-][\\w-]*)*'
+            javascript: '/^[a-zA-Z][a-zA-Z0-9-_]*$/',
+            python: 'r"^[a-zA-Z][a-zA-Z0-9-_]*$"',
+            php: '/^[a-zA-Z][a-zA-Z0-9-_]*$/',
+            java: '^[a-zA-Z][a-zA-Z0-9-_]*$'
         }
-    },
+    }
+};
 
-    // 数字验证类
-    'number': {
-        title: '数字验证',
-        description: '验证是否为纯数字',
+// 1. 补充下拉框正则项到regexDatabase
+const extraRegexPresets = [
+    // 常用字符
+    {
+        key: 'chinese-char',
+        title: '匹配中文字符',
+        category: '常用字符',
+        description: '匹配所有中文字符',
         patterns: {
-            javascript: '/^\d+$/',
-            python: 'r"^\d+$"',
-            php: '/^\d+$/',
+            javascript: '/[\u4e00-\u9fa5]/gm',
+            python: 'r"[\u4e00-\u9fa5]"',
+            php: '/[\\x{4e00}-\\x{9fa5}]/u',
+            java: '[\u4e00-\u9fa5]'
+        }
+    },
+    {
+        key: 'double-byte-char',
+        title: '匹配双字节字符',
+        category: '常用字符',
+        description: '匹配所有双字节字符',
+        patterns: {
+            javascript: '/[^\x00-\xff]/igm',
+            python: 'r"[^\x00-\xff]"',
+            php: '/[^\x00-\xff]/i',
+            java: '[^\x00-\xff]'
+        }
+    },
+    {
+        key: 'trim-line',
+        title: '匹配行尾行首空白',
+        category: '常用字符',
+        description: '匹配每行首尾的空白字符',
+        patterns: {
+            javascript: '/(^\\s*)|(\\s*$)/',
+            python: 'r"(^\\s*)|(\\s*$)"',
+            php: '/(^\\s*)|(\\s*$)/',
+            java: '(^\\s*)|(\\s*$)'
+        }
+    },
+    {
+        key: 'only-number',
+        title: '只能输入数字',
+        category: '常用字符',
+        description: '只能输入数字',
+        patterns: {
+            javascript: '/^\\d+$/',
+            python: 'r"^\\d+$"',
+            php: '/^\\d+$/',
             java: '^\\d+$'
         }
     },
-    'number-n-digits': {
-        title: 'n位数字验证',
-        description: '验证是否为n位数字(示例为4位)',
+    {
+        key: 'number-n',
+        title: '只能输入n个数字',
+        category: '常用字符',
+        description: '只能输入n个数字',
         patterns: {
-            javascript: '/^\d{4}$/',
-            python: 'r"^\d{4}$"',
-            php: '/^\d{4}$/',
-            java: '^\\d{4}$'
+            javascript: '/^\\d{n}$/',
+            python: 'r"^\\d{n}$"',
+            php: '/^\\d{n}$/',
+            java: '^\\d{n}$'
         }
     },
-    'number-min-n-digits': {
-        title: '至少n位数字验证',
-        description: '验证是否至少包含n位数字(示例为6位)',
+    {
+        key: 'number-min-n',
+        title: '至少输入n个以上的数字',
+        category: '常用字符',
+        description: '至少输入n个以上的数字',
         patterns: {
-            javascript: '/^\d{6,}$/',
-            python: 'r"^\d{6,}$"',
-            php: '/^\d{6,}$/',
-            java: '^\\d{6,}$'
+            javascript: '/^\\d{n,}$/',
+            python: 'r"^\\d{n,}$"',
+            php: '/^\\d{n,}$/',
+            java: '^\\d{n,}$'
         }
     },
-    'number-range-digits': {
-        title: '数字位数范围验证',
-        description: '验证数字位数是否在指定范围内(示例为6-18位)',
+    {
+        key: 'number-m-n',
+        title: '只能输入m到n个数字',
+        category: '常用字符',
+        description: '只能输入m到n个数字',
         patterns: {
-            javascript: '/^\d{6,18}$/',
-            python: 'r"^\d{6,18}$"',
-            php: '/^\d{6,18}$/',
-            java: '^\\d{6,18}$'
+            javascript: '/^\\d{m,n}$/',
+            python: 'r"^\\d{m,n}$"',
+            php: '/^\\d{m,n}$/',
+            java: '^\\d{m,n}$'
         }
     },
-    'decimal': {
-        title: '小数验证',
-        description: '验证是否为小数',
+    {
+        key: 'only-alpha',
+        title: '只能由英文字母组成',
+        category: '常用字符',
+        description: '只能由英文字母组成',
         patterns: {
-            javascript: '/^\d+\.\d+$/',
-            python: 'r"^\d+\.\d+$"',
-            php: '/^\d+\.\d+$/',
-            java: '^\\d+\\.\\d+$'
+            javascript: '/^[a-z]+$/i',
+            python: 'r"^[a-zA-Z]+$"',
+            php: '/^[a-zA-Z]+$/',
+            java: '^[a-zA-Z]+$'
         }
     },
-    'integer': {
-        title: '整数验证',
-        description: '验证是否为整数(包括正负整数)',
+    {
+        key: 'only-uppercase',
+        title: '只能由大写英文字母组成',
+        category: '常用字符',
+        description: '只能由大写英文字母组成',
         patterns: {
-            javascript: '/^-?\\d+$/',
-            python: 'r"^-?\\d+$"',
-            php: '/^-?\\d+$/',
-            java: '^-?\\d+$'
+            javascript: '/^[A-Z]+$/',
+            python: 'r"^[A-Z]+$"',
+            php: '/^[A-Z]+$/',
+            java: '^[A-Z]+$'
         }
     },
-
-    // 文本格式类
-    'chinese-name': {
-        title: '中文姓名验证',
-        description: '验证中文姓名(2-6个汉字)',
+    {
+        key: 'alpha-number',
+        title: '只能由英文和数字组成',
+        category: '常用字符',
+        description: '只能由英文和数字组成',
         patterns: {
-            javascript: '/^[\\u4e00-\\u9fa5]{2,6}$/',
-            python: 'r"^[\\u4e00-\\u9fa5]{2,6}$"',
-            php: '/^[\\x{4e00}-\\x{9fa5}]{2,6}$/u',
-            java: '^[\\u4e00-\\u9fa5]{2,6}$'
+            javascript: '/^[a-z0-9]+$/i',
+            python: 'r"^[a-zA-Z0-9]+$"',
+            php: '/^[a-zA-Z0-9]+$/',
+            java: '^[a-zA-Z0-9]+$'
         }
     },
-    'english-name': {
-        title: '英文姓名验证',
-        description: '验证英文姓名(支持空格和点号)',
+    {
+        key: 'alpha-number-underscore',
+        title: '只能由英文、数字、下划线组成',
+        category: '常用字符',
+        description: '只能由英文、数字、下划线组成',
         patterns: {
-            javascript: '/^[a-zA-Z][a-zA-Z\\s\\.]{0,58}[a-zA-Z]$/',
-            python: 'r"^[a-zA-Z][a-zA-Z\\s\\.]{0,58}[a-zA-Z]$"',
-            php: '/^[a-zA-Z][a-zA-Z\\s\\.]{0,58}[a-zA-Z]$/',
-            java: '^[a-zA-Z][a-zA-Z\\s\\.]{0,58}[a-zA-Z]$'
+            javascript: '/^\\w+$/',
+            python: 'r"^\\w+$"',
+            php: '/^\\w+$/',
+            java: '^\\w+$'
         }
     },
-    'username': {
-        title: '用户名验证',
-        description: '验证用户名(字母开头,允许5-16字节,允许字母数字下划线)',
+    // 常用表单
+    {
+        key: 'email-simple',
+        title: '匹配Email地址',
+        category: '常用表单',
+        description: '匹配Email地址',
         patterns: {
-            javascript: '/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/',
-            python: 'r"^[a-zA-Z][a-zA-Z0-9_]{4,15}$"',
-            php: '/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/',
-            java: '^[a-zA-Z][a-zA-Z0-9_]{4,15}$'
+            javascript: '/\w+([-+.\w+])*@\w+([-.]\w+)*\.\w+([-.]\w+)*/',
+            python: 'r"\w+[\-+.\w+]*@\w+[\-.\w+]*\.\w+[\-.\w+]*"',
+            php: '/\w+([-+.\w+])*@\w+([-.]\w+)*\.\w+([-.]\w+)*/',
+            java: '\w+([-+.\w+])*@\w+([-.]\w+)*\.\w+([-.]\w+)*'
         }
     },
-    'password-strong': {
-        title: '强密码验证',
-        description: '验证密码强度(必须包含大小写字母和数字,可以包含特殊字符,长度8-16)',
+    {
+        key: 'url-simple',
+        title: '匹配URL地址',
+        category: '常用表单',
+        description: '匹配URL地址',
         patterns: {
-            javascript: '/^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9!@#$%^&*]{8,16}$/',
-            python: 'r"^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9!@#$%^&*]{8,16}$"',
-            php: '/^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9!@#$%^&*]{8,16}$/',
-            java: '^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9!@#$%^&*]{8,16}$'
+            javascript: '/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(?::\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i',
+            python: 'r"^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(?::\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$"',
+            php: '/^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(?::\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$/i',
+            java: '^https?:\/\/(([a-zA-Z0-9_-])+(\.)?)*(?::\d+)?(\/((\.)?(\?)?=?&?[a-zA-Z0-9_-](\?)?)*)*$'
         }
     },
-
-    // 特殊格式类
-    'mac-address': {
-        title: 'MAC地址验证',
-        description: '验证MAC地址格式',
+    {
+        key: 'mobile-cn',
+        title: '匹配手机号码',
+        category: '常用表单',
+        description: '匹配中国大陆手机号码',
         patterns: {
-            javascript: '/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/',
-            python: 'r"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"',
-            php: '/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/',
-            java: '^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$'
+            javascript: '/^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$/',
+            python: 'r"^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$"',
+            php: '/^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$/',
+            java: '^(0|86|17951)?(13[0-9]|15[012356789]|166|17[3678]|18[0-9]|14[57])[0-9]{8}$'
         }
     },
-    'hex-color': {
-        title: '16进制颜色验证',
-        description: '验证16进制颜色代码',
+    {
+        key: 'idcard-mix',
+        title: '匹配身份证号',
+        category: '常用表单',
+        description: '匹配中国大陆身份证号',
         patterns: {
-            javascript: '/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/',
-            python: 'r"^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$"',
-            php: '/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/',
-            java: '^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$'
+            javascript: '/^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/',
+            python: 'r"(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)"',
+            php: '/^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)$/',
+            java: '(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[Xx])$)'
         }
     },
-    'version-number': {
-        title: '版本号验证',
-        description: '验证版本号格式(x.y.z)',
+    {
+        key: 'postal-code',
+        title: '匹配邮编号',
+        category: '常用表单',
+        description: '匹配中国邮政编码',
         patterns: {
-            javascript: '/^\\d+\\.\\d+\\.\\d+$/',
-            python: 'r"^\\d+\\.\\d+\\.\\d+$"',
-            php: '/^\\d+\\.\\d+\\.\\d+$/',
-            java: '^\\d+\\.\\d+\\.\\d+$'
+            javascript: '/^[1-9]\d{5}(?!\d)$/',
+            python: 'r"^[1-9]\d{5}(?!\d)$"',
+            php: '/^[1-9]\d{5}(?!\d)$/',
+            java: '^[1-9]\d{5}(?!\d)$'
+        }
+    },
+    {
+        key: 'date-ymd',
+        title: '匹配日期(yyyy-MM-dd)',
+        category: '常用表单',
+        description: '匹配日期格式(yyyy-MM-dd)',
+        patterns: {
+            javascript: '/^[1-2][0-9][0-9][0-9]-[0-1]{0,1}[0-9]-[0-3]{0,1}[0-9]$/',
+            python: 'r"^[1-2][0-9][0-9][0-9]-[0-1]{0,1}[0-9]-[0-3]{0,1}[0-9]$"',
+            php: '/^[1-2][0-9][0-9][0-9]-[0-1]{0,1}[0-9]-[0-3]{0,1}[0-9]$/',
+            java: '^[1-2][0-9][0-9][0-9]-[0-1]{0,1}[0-9]-[0-3]{0,1}[0-9]$'
+        }
+    },
+    {
+        key: 'car-plate-blue',
+        title: '匹配车牌号(蓝牌)',
+        category: '常用表单',
+        description: '匹配中国大陆蓝牌车牌号',
+        patterns: {
+            javascript: '/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{4}[A-Z0-9挂学警港澳]$/',
+            python: 'r"^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{4}[A-Z0-9挂学警港澳]$"',
+            php: '/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{4}[A-Z0-9挂学警港澳]$/',
+            java: '^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{4}[A-Z0-9挂学警港澳]$'
+        }
+    },
+    {
+        key: 'car-plate-green',
+        title: '匹配车牌号(绿牌)',
+        category: '常用表单',
+        description: '匹配中国大陆绿牌车牌号',
+        patterns: {
+            javascript: '/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{5}[A-Z0-9挂学警港澳]$/',
+            python: 'r"^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{5}[A-Z0-9挂学警港澳]$"',
+            php: '/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{5}[A-Z0-9挂学警港澳]$/',
+            java: '^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z][A-Z][A-Z0-9]{5}[A-Z0-9挂学警港澳]$'
+        }
+    },
+    // 浏览器UA
+    {
+        key: 'ua-ie',
+        title: '从UA判断是否为IE浏览器',
+        category: '浏览器UA',
+        description: '匹配IE浏览器的userAgent',
+        patterns: {
+            javascript: '/msie (\\d+\\.\\d+)/i',
+            python: 'r"msie (\\d+\\.\\d+)"',
+            php: '/msie (\\d+\\.\\d+)/i',
+            java: 'msie (\\d+\\.\\d+)' 
+        }
+    },
+    {
+        key: 'ua-webkit',
+        title: '从UA判断是否为webkit内核',
+        category: '浏览器UA',
+        description: '匹配webkit内核的userAgent',
+        patterns: {
+            javascript: '/webkit/i',
+            python: 'r"webkit"',
+            php: '/webkit/i',
+            java: 'webkit'
+        }
+    },
+    {
+        key: 'ua-chrome',
+        title: '从UA判断是否为chrome浏览器',
+        category: '浏览器UA',
+        description: '匹配chrome浏览器的userAgent',
+        patterns: {
+            javascript: '/chrome\\/(\\d+\\.\\d+)/i',
+            python: 'r"chrome/(\\d+\\.\\d+)"',
+            php: '/chrome\\/(\\d+\\.\\d+)/i',
+            java: 'chrome/(\\d+\\.\\d+)'
+        }
+    },
+    {
+        key: 'ua-firefox',
+        title: '从UA判断是否为firefox浏览器',
+        category: '浏览器UA',
+        description: '匹配firefox浏览器的userAgent',
+        patterns: {
+            javascript: '/firefox\\/(\\d+\\.\\d+)/i',
+            python: 'r"firefox/(\\d+\\.\\d+)"',
+            php: '/firefox\\/(\\d+\\.\\d+)/i',
+            java: 'firefox/(\\d+\\.\\d+)'
+        }
+    },
+    {
+        key: 'ua-opera',
+        title: '从UA判断是否为opera浏览器',
+        category: '浏览器UA',
+        description: '匹配opera浏览器的userAgent',
+        patterns: {
+            javascript: '/opera(\\/| )(\\d+(\\.\\d+)?)(.+?(version\\/(\\d+(\\.\\d+)?)))?/i',
+            python: 'r"opera(/| )(\\d+(\\.\\d+)?)(.+?(version/(\\d+(\\.\\d+)?)))?"',
+            php: '/opera(\\/| )(\\d+(\\.\\d+)?)(.+?(version\\/(\\d+(\\.\\d+)?)))?/i',
+            java: 'opera(/| )(\\d+(\\.\\d+)?)(.+?(version/(\\d+(\\.\\d+)?)))?'
+        }
+    },
+    {
+        key: 'ua-safari',
+        title: '从UA判断是否为Safari浏览器',
+        category: '浏览器UA',
+        description: '匹配Safari浏览器的userAgent',
+        patterns: {
+            javascript: '/(\\d+\\.\\d)?(?:\\.\\d)?\\s+safari\\/?(\\d+\\.\\d+)?/i',
+            python: 'r"(\\d+\\.\\d)?(?:\\.\\d)?\\s+safari/?(\\d+\\.\\d+)?"',
+            php: '/(\\d+\\.\\d)?(?:\\.\\d)?\\s+safari\\/?(\\d+\\.\\d+)?/i',
+            java: '(\\d+\\.\\d)?(?:\\.\\d)?\\s+safari/?(\\d+\\.\\d+)?'
+        }
+    },
+    {
+        key: 'ua-android',
+        title: '从UA中判断是否为Android系统',
+        category: '浏览器UA',
+        description: '匹配Android系统的userAgent',
+        patterns: {
+            javascript: '/android/i',
+            python: 'r"android"',
+            php: '/android/i',
+            java: 'android'
+        }
+    },
+    {
+        key: 'ua-ipad',
+        title: '从UA中判断是否为iPad',
+        category: '浏览器UA',
+        description: '匹配iPad的userAgent',
+        patterns: {
+            javascript: '/ipad/i',
+            python: 'r"ipad"',
+            php: '/ipad/i',
+            java: 'ipad'
+        }
+    },
+    {
+        key: 'ua-iphone',
+        title: '从UA中判断是否为iPhone',
+        category: '浏览器UA',
+        description: '匹配iPhone的userAgent',
+        patterns: {
+            javascript: '/iphone/i',
+            python: 'r"iphone"',
+            php: '/iphone/i',
+            java: 'iphone'
+        }
+    },
+    {
+        key: 'ua-mac',
+        title: '从UA判断是否为Mac OS平台',
+        category: '浏览器UA',
+        description: '匹配Mac OS的userAgent',
+        patterns: {
+            javascript: '/macintosh/i',
+            python: 'r"macintosh"',
+            php: '/macintosh/i',
+            java: 'macintosh'
+        }
+    },
+    {
+        key: 'ua-windows',
+        title: '从UA中判断是否为Windows平台',
+        category: '浏览器UA',
+        description: '匹配Windows平台的userAgent',
+        patterns: {
+            javascript: '/windows/i',
+            python: 'r"windows"',
+            php: '/windows/i',
+            java: 'windows'
+        }
+    },
+    {
+        key: 'ua-mobile',
+        title: '从UA中判断是否为移动终端',
+        category: '浏览器UA',
+        description: '匹配移动终端的userAgent',
+        patterns: {
+            javascript: '/(nokia|iphone|android|ipad|motorola|^mot\-|softbank|foma|docomo|kddi|up\\.browser|up\\.link|htc|dopod|blazer|netfront|helio|hosin|huawei|novarra|CoolPad|webos|techfaith|palmsource|blackberry|alcatel|amoi|ktouch|nexian|samsung|^sam\-|s[cg]h|^lge|ericsson|philips|sagem|wellcom|bunjalloo|maui|symbian|smartphone|midp|wap|phone|windows ce|iemobile|^spice|^bird|^zte\-|longcos|pantech|gionee|^sie\-|portalmmm|jig\\s browser|hiptop|^ucweb|^benq|haier|^lct|opera\\s*mobi|opera\*mini|320x320|240x320|176x220)/i',
+            python: 'r"(nokia|iphone|android|ipad|motorola|^mot\-|softbank|foma|docomo|kddi|up\\.browser|up\\.link|htc|dopod|blazer|netfront|helio|hosin|huawei|novarra|CoolPad|webos|techfaith|palmsource|blackberry|alcatel|amoi|ktouch|nexian|samsung|^sam\-|s[cg]h|^lge|ericsson|philips|sagem|wellcom|bunjalloo|maui|symbian|smartphone|midp|wap|phone|windows ce|iemobile|^spice|^bird|^zte\-|longcos|pantech|gionee|^sie\-|portalmmm|jig\\s browser|hiptop|^ucweb|^benq|haier|^lct|opera\\s*mobi|opera\*mini|320x320|240x320|176x220)"',
+            php: '/(nokia|iphone|android|ipad|motorola|^mot\-|softbank|foma|docomo|kddi|up\\.browser|up\\.link|htc|dopod|blazer|netfront|helio|hosin|huawei|novarra|CoolPad|webos|techfaith|palmsource|blackberry|alcatel|amoi|ktouch|nexian|samsung|^sam\-|s[cg]h|^lge|ericsson|philips|sagem|wellcom|bunjalloo|maui|symbian|smartphone|midp|wap|phone|windows ce|iemobile|^spice|^bird|^zte\-|longcos|pantech|gionee|^sie\-|portalmmm|jig\\s browser|hiptop|^ucweb|^benq|haier|^lct|opera\\s*mobi|opera\*mini|320x320|240x320|176x220)/i',
+            java: '(nokia|iphone|android|ipad|motorola|^mot\-|softbank|foma|docomo|kddi|up\\.browser|up\\.link|htc|dopod|blazer|netfront|helio|hosin|huawei|novarra|CoolPad|webos|techfaith|palmsource|blackberry|alcatel|amoi|ktouch|nexian|samsung|^sam\-|s[cg]h|^lge|ericsson|philips|sagem|wellcom|bunjalloo|maui|symbian|smartphone|midp|wap|phone|windows ce|iemobile|^spice|^bird|^zte\-|longcos|pantech|gionee|^sie\-|portalmmm|jig\\s browser|hiptop|^ucweb|^benq|haier|^lct|opera\\s*mobi|opera\*mini|320x320|240x320|176x220)'
+        }
+    },
+    // HTML相关
+    {
+        key: 'html-link',
+        title: '匹配link标签',
+        category: 'HTML相关',
+        description: '匹配HTML中的link标签',
+        patterns: {
+            javascript: '/<link\\s(.*?)\\s*(([^&]>)|(\\/>)|(\\<\\/link>))/gi',
+            python: 'r"<link\\s(.*?)\\s*(([^&]>)|(\\/>)|(\\<\\/link>))"',
+            php: '/<link\\s(.*?)\\s*(([^&]>)|(\\/>)|(\\<\\/link>))/i',
+            java: '<link\\s(.*?)\\s*(([^&]>)|(\\/>)|(\\<\\/link>))'
+        }
+    },
+    {
+        key: 'html-tag',
+        title: '匹配HTML标签',
+        category: 'HTML相关',
+        description: '匹配HTML标签',
+        patterns: {
+            javascript: '/<(\\S*?) [^>]*>.*?<\\/\\1>|<.*?\/>/gm',
+            python: 'r"<(\\S*?) [^>]*>.*?</\\1>|<.*?/>"',
+            php: '/<(\\S*?) [^>]*>.*?<\\/\\1>|<.*?\/>/m',
+            java: '<(\\S*?) [^>]*>.*?</\\1>|<.*?/>'
+        }
+    },
+    {
+        key: 'not-html-tag',
+        title: '匹配非HTML标签',
+        category: 'HTML相关',
+        description: '匹配非HTML标签',
+        patterns: {
+            javascript: '/^[^<>`~!\/@#}$%:;)(_^{&*=|\'+]+$/',
+            python: 'r"^[^<>`~!/@#}$%:;)(_^{&*=|\'+]+$"',
+            php: '/^[^<>`~!\/@#}$%:;)(_^{&*=|\'+]+$/',
+            java: '^[^<>`~!/@#}$%:;)(_^{&*=|\'+]+$'
+        }
+    },
+    {
+        key: 'html-script',
+        title: '匹配script标签',
+        category: 'HTML相关',
+        description: '匹配script标签',
+        patterns: {
+            javascript: '/<script[^>]*>[\s\S]*?<\\/[^>]*script>/gi',
+            python: 'r"<script[^>]*>[\s\S]*?</[^>]*script>"',
+            php: '/<script[^>]*>[\s\S]*?<\\/[^>]*script>/i',
+            java: '<script[^>]*>[\s\S]*?</[^>]*script>'
+        }
+    },
+    {
+        key: 'html-comment',
+        title: '匹配HTML注释',
+        category: 'HTML相关',
+        description: '匹配HTML注释',
+        patterns: {
+            javascript: '/<!--[\s\S]*?--\\>/g',
+            python: 'r"<!--[\s\S]*?-->"',
+            php: '/<!--[\s\S]*?--\\>/',
+            java: '<!--[\s\S]*?-->'
+        }
+    },
+    {
+        key: 'html-cond-comment',
+        title: '匹配HTML条件注释',
+        category: 'HTML相关',
+        description: '匹配HTML条件注释',
+        patterns: {
+            javascript: '/\[\s*if\s+[^\]][\s\w]*\]/i',
+            python: 'r"\[\s*if\s+[^\]][\s\w]*\]"',
+            php: '/\[\s*if\s+[^\]][\s\w]*\]/i',
+            java: '\[\s*if\s+[^\]][\s\w]*\]'
+        }
+    },
+    {
+        key: 'html-cond-comment-not-ie',
+        title: '匹配非IE的条件注释',
+        category: 'HTML相关',
+        description: '匹配非IE的条件注释',
+        patterns: {
+            javascript: '/^\[if\s+(!IE|false)\]>.*<!\[endif\]$/i',
+            python: 'r"^\[if\s+(!IE|false)\]>.*<!\[endif\]$"',
+            php: '/^\[if\s+(!IE|false)\]>.*<!\[endif\]$/i',
+            java: '^\[if\s+(!IE|false)\]>.*<!\[endif\]$'
+        }
+    },
+    {
+        key: 'css-expression',
+        title: '匹配CSS expression',
+        category: 'HTML相关',
+        description: '匹配CSS expression',
+        patterns: {
+            javascript: '/expression[\s\r\n ]?\(/gi',
+            python: 'r"expression[\s\r\n ]?\("',
+            php: '/expression[\s\r\n ]?\(/i',
+            java: 'expression[\s\r\n ]?\('
+        }
+    },
+    {
+        key: 'illegal-html-tag',
+        title: '匹配不合法的HTML标签',
+        category: 'HTML相关',
+        description: '匹配不合法的HTML标签',
+        patterns: {
+            javascript: '/<\W+>/gi',
+            python: 'r"<\W+>"',
+            php: '/<\W+>/i',
+            java: '<\W+>'
+        }
+    },
+    {
+        key: 'html-textarea',
+        title: '匹配textarea标签',
+        category: 'HTML相关',
+        description: '匹配textarea标签',
+        patterns: {
+            javascript: '/<textarea[^>]*>[\s\S]*?<\\/[^>]*textarea>/gi',
+            python: 'r"<textarea[^>]*>[\s\S]*?</[^>]*textarea>"',
+            php: '/<textarea[^>]*>[\s\S]*?<\\/[^>]*textarea>/i',
+            java: '<textarea[^>]*>[\s\S]*?</[^>]*textarea>'
         }
     }
-};
+];
 
-// 初始化事件监听
-document.addEventListener('DOMContentLoaded', () => {
-    const modal = document.getElementById('regexModal');
-    const closeBtn = document.querySelector('.close');
-    const regexItems = document.querySelectorAll('.regex-item');
-    const copyButtons = document.querySelectorAll('.copy-btn');
-
-    // 点击正则表达式项显示模态框
-    regexItems.forEach(item => {
-        item.addEventListener('click', () => {
-            const regexId = item.getAttribute('data-regex-id');
-            const regexData = regexDatabase[regexId];
-            
-            if (regexData) {
-                document.getElementById('modalTitle').textContent = regexData.title;
-                document.getElementById('jsRegex').textContent = regexData.patterns.javascript;
-                document.getElementById('pythonRegex').textContent = regexData.patterns.python;
-                document.getElementById('phpRegex').textContent = regexData.patterns.php;
-                document.getElementById('javaRegex').textContent = regexData.patterns.java;
-                document.getElementById('regexDescription').textContent = regexData.description;
-                
-                modal.style.display = 'block';
-            }
-        });
+// 合并到regexDatabase(避免重复)
+extraRegexPresets.forEach(item => {
+    if (!regexDatabase[item.key]) {
+        regexDatabase[item.key] = item;
+    }
+});
+
+/**
+ * 自动生成旧版下拉框正则项到regexDatabase
+ */
+function populateOldVersionPreset() {
+    const select = document.getElementById('regList');
+    if (!select) return;
+    select.innerHTML = '';
+
+    // 添加自定义选项
+    const customOption = document.createElement('option');
+    customOption.value = '';
+    customOption.textContent = '自定义/选择常用正则';
+    select.appendChild(customOption);
+
+    // 按分类分组
+    const grouped = {};
+    Object.keys(regexDatabase).forEach(key => {
+        const item = regexDatabase[key];
+        const cat = item.category || '其他';
+        if (!grouped[cat]) grouped[cat] = [];
+        grouped[cat].push({ key, title: item.title, pattern: item.patterns.javascript });
     });
 
-    // 关闭模态框
-    closeBtn.addEventListener('click', () => {
-        modal.style.display = 'none';
+    Object.keys(grouped).forEach(cat => {
+        const group = document.createElement('optgroup');
+        group.label = cat;
+        grouped[cat].forEach(opt => {
+            const option = document.createElement('option');
+            option.value = opt.pattern;
+            option.textContent = opt.title;
+            group.appendChild(option);
+        });
+        select.appendChild(group);
     });
+}
 
-    // 点击模态框外部关闭
-    window.addEventListener('click', (event) => {
-        if (event.target === modal) {
-            modal.style.display = 'none';
+/**
+ * 自适应高度的jQuery插件 - 用于旧版功能
+ */
+if (typeof $ !== 'undefined') {
+    $.fn.extend({
+        textareaAutoHeight: function (options) {
+            this._options = {
+                minHeight: 0,
+                maxHeight: 100000
+            };
+
+            this.init = function () {
+                for (var p in options) {
+                    this._options[p] = options[p];
+                }
+                if (this._options.minHeight === 0) {
+                    this._options.minHeight = parseFloat($(this).height());
+                }
+                for (var p in this._options) {
+                    if ($(this).attr(p) == null) {
+                        $(this).attr(p, this._options[p]);
+                    }
+                }
+                $(this).keyup(this.resetHeight).change(this.resetHeight)
+                    .focus(this.resetHeight);
+            };
+            this.resetHeight = function () {
+                var _minHeight = parseFloat($(this).attr("minHeight"));
+                var _maxHeight = parseFloat($(this).attr("maxHeight"));
+
+                $(this).height(0);
+                var h = parseFloat(this.scrollHeight);
+                h = h < _minHeight ? _minHeight :
+                    h > _maxHeight ? _maxHeight : h;
+                $(this).height(h).scrollTop(h);
+                if (h >= _maxHeight) {
+                    $(this).css("overflow-y", "scroll");
+                }
+                else {
+                    $(this).css("overflow-y", "hidden");
+                }
+            };
+            this.init();
         }
     });
+}
+
+/**
+ * 旧版正则表达式工具类
+ */
+var RegExpTools = (function () {
+    "use strict";
 
+    var regElm, srcElm, rstElm, rstCount, srcBackgroundElm, srcWrapperElm, regListElm;
+    var ID_PREFIX = 'tmp_id_';
+    var TAG_MATCHED = 'b';
+    var TAG_NOT_MATCHED = 'i';
+    var TR_ID_PREFIX = 'tr_' + ID_PREFIX;
+
+    var _getRegExp = function (regTxt) {
+        try {
+            return new Function('return ' + regTxt)();
+        } catch (e) {
+            return null;
+        }
+    };
 
-    // 点击模态框外部关闭
-    document.getElementById('donate-link').addEventListener('click', (event) => {
-        event.preventDefault();
-        event.stopPropagation();
-        chrome.runtime.sendMessage({
-            type: 'fh-dynamic-any-thing',
-            thing: 'open-donate-modal',
-            params: { toolName: 'regexp' }
+    var _buildTable = function (rstArray) {
+        var tbl = ["<table class='table table-bordered table-striped table-condensed table-hover'>"];
+        tbl.push('<tr class="active"><th class="num">序号</th><th>匹配结果</th><th>在原字符串中的位置</th></tr>')
+        $.each(rstArray, function (i, item) {
+            tbl.push('<tr id="' + TR_ID_PREFIX + item.index + '" data-index="' + item.index + '">');
+            tbl.push('<td class="num">' + (i + 1) + '</td>'
+                + '<td class="content">' + item.text + '</td>'
+                + '<td class="index">' + item.index + '</td>');
+            tbl.push('</tr>');
         });
-        return false;
-    });
+        tbl.push('</table>');
+        return tbl.join('');
+    };
+
+    var _createTag = function (type, item) {
+        var tags = [];
+        for (var i = 0, len = item.text.length; i < len; i++) {
+            tags.push('<' + type + ' data-id="' + ID_PREFIX + item.index + '">'
+                + item.text.charAt(i) + '</' + type + '>');
+        }
+        return tags.join('');
+    };
+
+    var _blinkHighlight = function () {
+        $('tr[id^=' + TR_ID_PREFIX + ']').click(function (e) {
+            var index = $(this).attr('data-index');
+            var tags = $(TAG_MATCHED + '[data-id=' + ID_PREFIX + index + ']');
+            tags.animate({
+                opacity: 0
+            }, 200).delay().animate({
+                opacity: 1
+            }, 200).delay().animate({
+                opacity: 0
+            }, 200).delay().animate({
+                opacity: 1
+            }, 200);
+        });
+    };
+
+    var _highlight = function (srcText, rstArray) {
+        if (!srcText) {
+            srcBackgroundElm.html('');
+            return;
+        }
+        var hl = [];
+        var preIndex = 0;
+        $.each(rstArray, function (i, item) {
+            if (i === 0) {
+                if (item.index === 0) {
+                    hl.push(_createTag(TAG_MATCHED, item));
+                } else {
+                    hl.push(_createTag(TAG_NOT_MATCHED, {
+                        index: 0,
+                        text: srcText.substring(0, item.index)
+                    }));
+                    hl.push(_createTag(TAG_MATCHED, item));
+                }
+            } else {
+                preIndex = rstArray[i - 1].index + rstArray[i - 1].text.length;
+                hl.push(_createTag(TAG_NOT_MATCHED, {
+                    index: preIndex,
+                    text: srcText.substring(preIndex, item.index)
+                }));
+                hl.push(_createTag(TAG_MATCHED, item));
+            }
+        });
+        srcBackgroundElm.html(hl.join(''));
+        _blinkHighlight();
+    };
+
+    var _emptyTable = function (message) {
+        var tbl = ["<table class='table table-bordered table-striped table-condensed table-hover'>"];
+        tbl.push('<tr class="active"><th class="num">序号</th><th>匹配结果</th></tr>');
+        tbl.push('<tr><td colspan="2">' + message + '</td></tr>');
+        tbl.push('</table>');
+        return tbl.join('');
+    };
+
+    var _dealRegMatch = function (e) {
+        if (!srcWrapperElm || !srcElm) return;
+        
+        srcWrapperElm.height(srcElm.height() + 24);
+
+        var regTxt = regElm.val().trim();
+        var srcTxt = srcElm.val().trim();
+        if (!regTxt || !srcTxt) {
+            rstElm.html(_emptyTable('不能匹配'));
+            rstCount.html('0个');
+            _highlight();
+        } else {
+            var reg = _getRegExp(regTxt);
+            if (!reg || !reg instanceof RegExp) {
+                rstElm.html(_emptyTable('正则表达式错误!'));
+                rstCount.html('0个');
+                _highlight();
+                return;
+            }
+            var rst = [];
+            // 用字符串的replace方法来找到匹配目标在元字符串中的准确位置
+            srcTxt.replace(reg, function () {
+                var matchedTxt = arguments[0];
+                var txtIndex = arguments[arguments.length - 2];
+                rst.push({
+                    text: matchedTxt,
+                    index: txtIndex
+                });
+            });
+            if (!rst || !rst.length) {
+                rstElm.html(_emptyTable('不能匹配'));
+                rstCount.html('0个');
+                _highlight();
+            } else {
+                rstElm.html(_buildTable(rst));
+                rstCount.html(rst.length + '个');
+                _highlight(srcElm.val(), rst);
+            }
+        }
+    };
+
+    var _init = function () {
+        regElm = $('#regText');
+        srcElm = $('#srcCode');
+        srcBackgroundElm = $('#srcBackground');
+        srcWrapperElm = $('#srcWrapper');
+        rstElm = $('#rstCode');
+        rstCount = $('#rstCount');
+        regListElm = $('#regList');
+
+        if (!regElm.length) return; // 如果元素不存在,直接返回
+
+        rstElm.html(_emptyTable('暂无输入'));
 
-    document.getElementById('other-tools').addEventListener('click', (event) => {
-        event.preventDefault();
-        event.stopPropagation();
-        chrome.runtime.openOptionsPage();
-        return false;
+        // 输入框自适应高度
+        if (regElm.textareaAutoHeight) {
+            regElm.textareaAutoHeight({ minHeight: 40 });
+            srcElm.textareaAutoHeight({ minHeight: 60 });
+            srcBackgroundElm.textareaAutoHeight({ minHeight: 60 });
+        }
+
+        // 监听两个输入框的按键、paste、change事件
+        $('#regText,#srcCode').keyup(_dealRegMatch).change(_dealRegMatch)
+            .bind('paste', _dealRegMatch);
+
+        regListElm.change(function (e) {
+            var reg = $(this).val();
+            var regTipElm = $('#regTip');
+            regElm.val(reg);
+            if (!reg) {
+                if (regTipElm.length) regTipElm.hide();
+            } else {
+                if (regTipElm.length) regTipElm.show();
+            }
+            _dealRegMatch(); // 触发匹配
+        });
+    };
+
+    return {
+        init: _init
+    };
+})();
+
+// 主要的应用程序逻辑
+document.addEventListener('DOMContentLoaded', function() {
+    initTabSwitching();
+    initNewVersionFeatures();
+    initOldVersionFeatures();
+    initCommonFeatures();
+});
+
+/**
+ * 初始化Tab切换功能
+ */
+function initTabSwitching() {
+    const tabBtns = document.querySelectorAll('.tab-btn');
+    const tabContents = document.querySelectorAll('.tab-content');
+
+    tabBtns.forEach(btn => {
+        btn.addEventListener('click', function() {
+            const targetTab = this.getAttribute('data-tab');
+            
+            // 移除所有active类
+            tabBtns.forEach(b => b.classList.remove('active'));
+            tabContents.forEach(c => c.classList.remove('active'));
+            
+            // 添加active类到当前选中的
+            this.classList.add('active');
+            document.getElementById(targetTab).classList.add('active');
+        });
     });
+}
 
-    // 复制按钮功能
-    copyButtons.forEach(button => {
-        button.addEventListener('click', () => {
-            const targetId = button.getAttribute('data-target');
-            const codeElement = document.getElementById(targetId);
-            const text = codeElement.textContent;
-
-            navigator.clipboard.writeText(text).then(() => {
-                const originalText = button.textContent;
-                button.textContent = '已复制!';
-                button.style.backgroundColor = '#27ae60';
-                
-                setTimeout(() => {
-                    button.textContent = originalText;
-                    button.style.backgroundColor = '#3498db';
-                }, 2000);
-            }).catch(err => {
-                console.error('复制失败:', err);
-                button.textContent = '复制失败';
-                button.style.backgroundColor = '#e74c3c';
-                
-                setTimeout(() => {
-                    button.textContent = '复制';
-                    button.style.backgroundColor = '#3498db';
-                }, 2000);
+/**
+ * 初始化新版功能
+ */
+function initNewVersionFeatures() {
+    populateVisualRegexPreset();
+    initVisualDebugger();
+    initRegexSearch();
+    initRegexItems();
+    initModal();
+}
+
+/**
+ * 初始化旧版功能
+ */
+function initOldVersionFeatures() {
+    // 确保jQuery已加载后再初始化旧版功能
+    if (typeof $ !== 'undefined') {
+        // 自动生成下拉框内容
+        populateOldVersionPreset();
+        RegExpTools.init();
+    }
+}
+
+/**
+ * 初始化通用功能
+ */
+function initCommonFeatures() {
+    // 打赏和其他工具链接
+    const donateLink = document.getElementById('donateLink');
+    const otherToolsBtn = document.getElementById('btnOtherTools');
+
+    if (donateLink) {
+        donateLink.addEventListener('click', function(event) {
+            event.preventDefault();
+            event.stopPropagation();
+            chrome.runtime.sendMessage({
+                type: 'fh-dynamic-any-thing',
+                thing: 'open-donate-modal',
+                params: { toolName: 'regexp' }
             });
         });
+    }
+
+    if (otherToolsBtn) {
+        otherToolsBtn.addEventListener('click', function(event) {
+            event.preventDefault();
+            event.stopPropagation();
+            chrome.runtime.openOptionsPage();
+        });
+    }
+}
+
+/**
+ * 填充可视化调试器的预设正则表达式
+ */
+function populateVisualRegexPreset() {
+    const select = document.getElementById('visualRegexPreset');
+    if (!select) return;
+
+    // 先清空
+    select.innerHTML = '';
+
+    // 添加自定义选项
+    const customOption = document.createElement('option');
+    customOption.value = '';
+    customOption.textContent = '自定义/选择常用正则';
+    select.appendChild(customOption);
+
+    // 按分类分组
+    const grouped = {};
+    Object.keys(regexDatabase).forEach(key => {
+        const item = regexDatabase[key];
+        const cat = item.category || '其他';
+        if (!grouped[cat]) grouped[cat] = [];
+        grouped[cat].push({ key, title: item.title });
+    });
+
+    Object.keys(grouped).forEach(cat => {
+        const group = document.createElement('optgroup');
+        group.label = cat;
+        grouped[cat].forEach(opt => {
+            const option = document.createElement('option');
+            option.value = opt.key;
+            option.textContent = opt.title;
+            group.appendChild(option);
+        });
+        select.appendChild(group);
     });
-});
 
-// 搜索功能实现
-document.addEventListener('DOMContentLoaded', function() {
-    const searchInput = document.getElementById('regexSearch');
-    const regexItems = document.querySelectorAll('.regex-item');
+    // 事件绑定逻辑不变
+    select.addEventListener('change', function() {
+        const selectedKey = this.value;
+        if (selectedKey && regexDatabase[selectedKey]) {
+            const pattern = regexDatabase[selectedKey].patterns.javascript;
+            // 去掉前后的斜杠和标志
+            const cleanPattern = pattern.replace(/^\/?|\/[gimuy]*$/g, '');
+            document.getElementById('visualRegex').value = cleanPattern;
+        }
+    });
+}
+
+/**
+ * 初始化可视化调试器
+ */
+function initVisualDebugger() {
+    const testBtn = document.getElementById('visualTestBtn');
+    const regexInput = document.getElementById('visualRegex');
+    const testTextArea = document.getElementById('visualTestText');
+    const resultDiv = document.getElementById('visualResult');
+    const errorMsg = document.getElementById('visualErrorMsg');
+    const flagCheckboxes = document.querySelectorAll('.flag-btn input[type="checkbox"]');
+
+    if (!testBtn) return;
+
+    // 标志复选框事件
+    flagCheckboxes.forEach(checkbox => {
+        checkbox.addEventListener('change', updateFlagsInputFromCheckbox);
+    });
+
+    function updateFlagsInputFromCheckbox() {
+        const flags = Array.from(flagCheckboxes)
+            .filter(cb => cb.checked)
+            .map(cb => cb.value)
+            .join('');
+        document.getElementById('visualFlags').value = flags;
+    }
+
+    testBtn.addEventListener('click', doVisualTest);
+    regexInput.addEventListener('keyup', function(e) {
+        if (e.key === 'Enter') doVisualTest();
+    });
+    testTextArea.addEventListener('keyup', function(e) {
+        if (e.key === 'Enter' && e.ctrlKey) doVisualTest();
+    });
+
+    // 新增:输入时自动实时匹配
+    regexInput.addEventListener('input', doVisualTest);
+    testTextArea.addEventListener('input', doVisualTest);
+
+    function doVisualTest() {
+        let regexStr = regexInput.value.trim();
+        const testText = testTextArea.value.trim();
+
+        errorMsg.textContent = '';
+
+        if (!regexStr) {
+            errorMsg.textContent = '请输入正则表达式';
+            return;
+        }
+        if (!testText) {
+            errorMsg.textContent = '请输入要测试的文本';
+            return;
+        }
+
+        // 新增:支持 /pattern/flags 写法
+        let pattern = regexStr;
+        let flags = Array.from(flagCheckboxes)
+            .filter(cb => cb.checked)
+            .map(cb => cb.value)
+            .join('');
+
+        // 如果是 /pattern/flags 形式
+        const regSlash = /^\/(.+)\/([gimsuy]*)$/;
+        const match = regexStr.match(regSlash);
+        if (match) {
+            pattern = match[1];
+            flags = match[2];
+        }
+
+        try {
+            const regex = new RegExp(pattern, flags);
+            const matches = [];
+            let match;
+            
+            if (flags.includes('g')) {
+                while ((match = regex.exec(testText)) !== null) {
+                    matches.push({
+                        match: match[0],
+                        index: match.index,
+                        groups: match.slice(1)
+                    });
+                    if (match.index === regex.lastIndex) break;
+                }
+            } else {
+                match = regex.exec(testText);
+                if (match) {
+                    matches.push({
+                        match: match[0],
+                        index: match.index,
+                        groups: match.slice(1)
+                    });
+                }
+            }
+            
+            displayVisualResults(matches, testText, regex);
+        } catch (e) {
+            errorMsg.textContent = '正则表达式语法错误: ' + e.message;
+            resultDiv.innerHTML = '';
+        }
+    }
+
+    function displayVisualResults(matches, text, regex) {
+        if (matches.length === 0) {
+            resultDiv.innerHTML = '<div class="no-matches">没有找到匹配项</div>';
+            return;
+        }
 
-    searchInput.addEventListener('input', function(e) {
-        const searchTerm = e.target.value.toLowerCase().trim();
+        let html = `<div class="match-summary">找到 ${matches.length} 个匹配项</div>`;
         
-        regexItems.forEach(item => {
-            const text = item.textContent.toLowerCase();
-            const match = text.includes(searchTerm);
+        // 高亮显示文本
+        let highlightedText = text;
+        let offset = 0;
+        
+        matches.forEach((match, index) => {
+            const startTag = `<mark class="match-highlight" data-match="${index}">`;
+            const endTag = '</mark>';
+            const insertPos = match.index + offset;
             
-            item.classList.toggle('hidden', !match);
-            item.classList.toggle('highlight', match && searchTerm !== '');
+            highlightedText = highlightedText.slice(0, insertPos) + 
+                            startTag + 
+                            highlightedText.slice(insertPos, insertPos + match.match.length) + 
+                            endTag + 
+                            highlightedText.slice(insertPos + match.match.length);
             
-            // 处理分类标题的显示/隐藏
-            const category = item.closest('.category');
-            const visibleItems = category.querySelectorAll('.regex-item:not(.hidden)');
-            category.style.display = visibleItems.length > 0 ? 'block' : 'none';
+            offset += startTag.length + endTag.length;
+        });
+        
+        html += `<div class="highlighted-text"><pre>${highlightedText}</pre></div>`;
+        
+        // 匹配详情
+        html += '<div class="match-details">';
+        matches.forEach((match, index) => {
+            html += `<div class="match-item">
+                <strong>匹配 ${index + 1}:</strong> "${match.match}" 
+                <span class="match-position">(位置: ${match.index}-${match.index + match.match.length - 1})</span>`;
+            
+            if (match.groups.length > 0) {
+                html += '<div class="match-groups">分组: ';
+                match.groups.forEach((group, groupIndex) => {
+                    if (group !== undefined) {
+                        html += `<span class="group">$${groupIndex + 1}: "${group}"</span> `;
+                    }
+                });
+                html += '</div>';
+            }
+            html += '</div>';
+        });
+        html += '</div>';
+        
+        resultDiv.innerHTML = html;
+    }
+}
+
+/**
+ * 初始化正则表达式搜索功能
+ */
+function initRegexSearch() {
+    const searchInput = document.getElementById('regexSearch');
+    if (!searchInput) return;
+
+    searchInput.addEventListener('input', function() {
+        const searchTerm = this.value.toLowerCase();
+        const regexItems = document.querySelectorAll('.regex-item');
+        const categories = document.querySelectorAll('.category-section');
+
+        if (!searchTerm) {
+            // 恢复所有分类和按钮显示
+            regexItems.forEach(item => {
+                item.style.display = '';
+            });
+            categories.forEach(cat => {
+                cat.style.display = '';
+            });
+            return;
+        }
+
+        // 原有筛选逻辑
+        regexItems.forEach(item => {
+            const text = item.textContent.toLowerCase();
+            const category = item.closest('.category-section');
+            if (text.includes(searchTerm)) {
+                item.style.display = 'block';
+                if (category) category.style.display = '';
+            } else {
+                item.style.display = 'none';
+            }
         });
+        // 隐藏没有可见项的分类
+        categories.forEach(category => {
+            const visibleItems = category.querySelectorAll('.regex-item[style*="block"], .regex-item:not([style*="none"])');
+            if (visibleItems.length === 0 && searchTerm) {
+                category.style.display = 'none';
+            } else if (!searchTerm) {
+                category.style.display = '';
+            }
+        });
+    });
+}
+
+/**
+ * 初始化正则表达式项目点击事件和新版分类按钮区域
+ * 自动遍历regexDatabase,按category分组渲染所有分类和按钮
+ */
+function initRegexItems() {
+    // 新版分类按钮区域容器
+    const container = document.getElementById('regexCategoryContainer');
+    if (!container) return;
+    container.innerHTML = '';
+
+    // 按分类分组
+    const grouped = {};
+    Object.keys(regexDatabase).forEach(key => {
+        const item = regexDatabase[key];
+        const cat = item.category || '其他';
+        if (!grouped[cat]) grouped[cat] = [];
+        grouped[cat].push({ key, title: item.title });
+    });
+
+    // 渲染每个分类
+    Object.keys(grouped).forEach(cat => {
+        // 分类标题
+        const section = document.createElement('div');
+        section.className = 'category-section';
+        section.innerHTML = `<div class="category-title">${cat}</div>`;
+        // 分类按钮区
+        const btnGroup = document.createElement('div');
+        btnGroup.className = 'category-btn-group';
+        grouped[cat].forEach(opt => {
+            const btn = document.createElement('button');
+            btn.className = 'regex-item';
+            btn.setAttribute('data-regex-id', opt.key);
+            btn.textContent = opt.title;
+            // 点击弹出模态框
+            btn.addEventListener('click', function() {
+                if (regexDatabase[opt.key]) {
+                    showRegexModal(regexDatabase[opt.key]);
+                } else {
+                    alert('该正则表达式暂未收录,敬请期待!');
+                }
+            });
+            btnGroup.appendChild(btn);
+        });
+        section.appendChild(btnGroup);
+        container.appendChild(section);
+    });
+}
+
+/**
+ * 初始化模态框
+ */
+function initModal() {
+    const modal = document.getElementById('regexModal');
+    const closeBtn = document.querySelector('.close');
+    
+    if (!modal) return;
+
+    closeBtn.addEventListener('click', function() {
+        modal.style.display = 'none';
     });
 
-    // 添加清空搜索框的快捷键(ESC)
-    searchInput.addEventListener('keydown', function(e) {
-        if (e.key === 'Escape') {
-            searchInput.value = '';
-            // 触发 input 事件以更新显示
-            searchInput.dispatchEvent(new Event('input'));
+    window.addEventListener('click', function(event) {
+        if (event.target === modal) {
+            modal.style.display = 'none';
         }
     });
-});
 
-// 正则可视化调试区域逻辑(升级版)
+    // 复制按钮事件
+    document.querySelectorAll('.copy-btn').forEach(btn => {
+        btn.addEventListener('click', function() {
+            const targetId = this.getAttribute('data-target');
+            const targetElement = document.getElementById(targetId);
+            
+            if (targetElement) {
+                const textToCopy = targetElement.textContent;
+                
+                if (navigator.clipboard) {
+                    navigator.clipboard.writeText(textToCopy).then(() => {
+                        this.textContent = '已复制!';
+                        setTimeout(() => {
+                            this.textContent = '复制';
+                        }, 2000);
+                    });
+                } else {
+                    // 降级方案
+                    const textArea = document.createElement('textarea');
+                    textArea.value = textToCopy;
+                    document.body.appendChild(textArea);
+                    textArea.select();
+                    document.execCommand('copy');
+                    document.body.removeChild(textArea);
+                    
+                    this.textContent = '已复制!';
+                    setTimeout(() => {
+                        this.textContent = '复制';
+                    }, 2000);
+                }
+            }
+        });
+    });
+}
+
+/**
+ * 显示正则表达式模态框
+ */
+function showRegexModal(regexData) {
+    const modal = document.getElementById('regexModal');
+    const modalTitle = document.getElementById('modalTitle');
+    const jsRegex = document.getElementById('jsRegex');
+    const pythonRegex = document.getElementById('pythonRegex');
+    const phpRegex = document.getElementById('phpRegex');
+    const javaRegex = document.getElementById('javaRegex');
+    const regexDescription = document.getElementById('regexDescription');
+
+    modalTitle.textContent = regexData.title;
+    jsRegex.textContent = regexData.patterns.javascript;
+    pythonRegex.textContent = regexData.patterns.python;
+    phpRegex.textContent = regexData.patterns.php;
+    javaRegex.textContent = regexData.patterns.java;
+    regexDescription.textContent = regexData.description;
+
+    modal.style.display = 'block';
+}
+
+// 工具函数
 function parsePatternAndFlags(input) {
-    // 自动识别 /pattern/flags 或 pattern
-    const match = input.match(/^\s*\/(.*)\/(\w*)\s*$/);
+    const match = input.match(/^\/(.+)\/([gimuy]*)$/);
     if (match) {
-        return { pattern: match[1], flags: match[2] };
+        return {
+            pattern: match[1],
+            flags: match[2]
+        };
     }
-    return { pattern: input, flags: '' };
+    return {
+        pattern: input,
+        flags: ''
+    };
 }
 
 function highlightMatchesV2(text, regex) {
-    if (!text) return '';
-    let lastIndex = 0;
-    let result = '';
-    let match;
-    let hasMatch = false;
-    regex.lastIndex = 0;
-    let count = 0;
-    while ((match = regex.exec(text)) !== null) {
-        hasMatch = true;
-        count++;
-        // 防止死循环
-        if (match[0] === '') {
-            result += text.slice(lastIndex);
-            break;
-        }
-        result += text.slice(lastIndex, match.index);
-        // 高亮主匹配内容
-        let main = '<span class="visual-match">' + match[0] + '</span>';
-        // 如果有分组,显示分组高亮
-        if (match.length > 1) {
-            let groupHtml = '';
-            for (let i = 1; i < match.length; i++) {
-                if (typeof match[i] === 'string') {
-                    groupHtml += `<span class="visual-group">$${i}: ${match[i]}</span> `;
-                }
-            }
-            main += '<span class="visual-group-list">' + groupHtml.trim() + '</span>';
-        }
-        result += main;
-        lastIndex = match.index + match[0].length;
-        if (!regex.global) break;
-    }
-    result += text.slice(lastIndex);
-    return { html: hasMatch ? result : text, count };
+    return text.replace(regex, '<mark>$&</mark>');
 }
 
 function loadPatchHotfix() {
-    // 页面加载时自动获取并注入页面的补丁
-    chrome.runtime.sendMessage({
-        type: 'fh-dynamic-any-thing',
-        thing: 'fh-get-tool-patch',
-        toolName: 'regexp'
-    }, patch => {
-        if (patch) {
-            if (patch.css) {
-                const style = document.createElement('style');
-                style.textContent = patch.css;
-                document.head.appendChild(style);
-            }
-            if (patch.js) {
-                try {
-                    if (window.evalCore && window.evalCore.getEvalInstance) {
-                        window.evalCore.getEvalInstance(window)(patch.js);
+    // 可以在这里添加热修复逻辑
+    console.log('正则表达式工具已加载');
+}
+
+// jQuery自适应高度插件(用于旧版功能)
+if (typeof $ !== 'undefined') {
+    $.fn.extend({
+        textareaAutoHeight: function (options) {
+            this._options = {
+                minHeight: 0,
+                maxHeight: 100000
+            };
+
+            this.init = function () {
+                for (var p in options) {
+                    this._options[p] = options[p];
+                }
+                if (this._options.minHeight === 0) {
+                    this._options.minHeight = parseFloat($(this).height());
+                }
+                for (var p in this._options) {
+                    if ($(this).attr(p) == null) {
+                        $(this).attr(p, this._options[p]);
                     }
-                } catch (e) {
-                    console.error('regexp补丁JS执行失败', e);
                 }
-            }
+                $(this).keyup(this.resetHeight).change(this.resetHeight)
+                    .focus(this.resetHeight);
+            };
+            this.resetHeight = function () {
+                var _minHeight = parseFloat($(this).attr("minHeight"));
+                var _maxHeight = parseFloat($(this).attr("maxHeight"));
+
+                $(this).height(0);
+                var h = parseFloat(this.scrollHeight);
+                h = h < _minHeight ? _minHeight :
+                    h > _maxHeight ? _maxHeight : h;
+                $(this).height(h).scrollTop(h);
+                if (h >= _maxHeight) {
+                    $(this).css("overflow-y", "scroll");
+                }
+                else {
+                    $(this).css("overflow-y", "hidden");
+                }
+            };
+            this.init();
         }
     });
 }
 
-document.addEventListener('DOMContentLoaded', function() {
-    // 可视化调试相关
-    const visualRegexPreset = document.getElementById('visualRegexPreset');
-    const visualRegexInput = document.getElementById('visualRegex');
-    const visualFlagsInput = document.getElementById('visualFlags');
-    const visualTestText = document.getElementById('visualTestText');
-    const visualTestBtn = document.getElementById('visualTestBtn');
-    const visualResult = document.getElementById('visualResult');
-    const visualErrorMsg = document.getElementById('visualErrorMsg');
-
-    // 动态填充下拉框
-    if (visualRegexPreset) {
-        for (const key in regexDatabase) {
-            if (regexDatabase[key].patterns && regexDatabase[key].patterns.javascript) {
-                const option = document.createElement('option');
-                option.value = key;
-                option.textContent = regexDatabase[key].title;
-                option.setAttribute('data-regex', regexDatabase[key].patterns.javascript);
-                visualRegexPreset.appendChild(option);
-            }
+// 旧版正则表达式工具类
+var RegExpTools = (function () {
+    "use strict";
+
+    var regElm, srcElm, rstElm, rstCount, srcBackgroundElm, srcWrapperElm, regListElm;
+    var ID_PREFIX = 'tmp_id_';
+    var TAG_MATCHED = 'b';
+    var TAG_NOT_MATCHED = 'i';
+    var TR_ID_PREFIX = 'tr_' + ID_PREFIX;
+
+    var _getRegExp = function (regTxt) {
+        try {
+            return new Function('return ' + regTxt)();
+        } catch (e) {
+            return null;
         }
-        // 标志按钮组与隐藏input联动
-        const flagCheckboxes = document.querySelectorAll('.visual-flags-group input[type="checkbox"]');
-        function updateFlagsInputFromCheckbox() {
-            let flags = '';
-            flagCheckboxes.forEach(cb => { if (cb.checked) flags += cb.value; });
-            visualFlagsInput.value = flags;
-            doVisualTest();
+    };
+
+    var _buildTable = function (rstArray) {
+        var tbl = ["<table class='table table-bordered table-striped table-condensed table-hover'>"];
+        tbl.push('<tr class="active"><th class="num">序号</th><th>匹配结果</th><th class="r-index">在原字符串中的位置</th></tr>')
+        $.each(rstArray, function (i, item) {
+            tbl.push('<tr id="' + TR_ID_PREFIX + item.index + '" data-index="' + item.index + '">');
+            tbl.push('<td class="num">' + (i + 1) + '</td>'
+                + '<td class="content">' + item.text + '</td>'
+                + '<td class="index">' + item.index + '</td>');
+            tbl.push('</tr>');
+        });
+        tbl.push('</table>');
+        return tbl.join('');
+    };
+
+    var _createTag = function (type, item) {
+        var tags = [];
+        for (var i = 0, len = item.text.length; i < len; i++) {
+            tags.push('<' + type + ' data-id="' + ID_PREFIX + item.index + '">'
+                + item.text.charAt(i) + '</' + type + '>');
         }
-        flagCheckboxes.forEach(cb => {
-            cb.addEventListener('change', updateFlagsInputFromCheckbox);
+        return tags.join('');
+    };
+
+    var _blinkHighlight = function () {
+        $('tr[id^=' + TR_ID_PREFIX + ']').click(function (e) {
+            var index = $(this).attr('data-index');
+            var tags = $(TAG_MATCHED + '[data-id=' + ID_PREFIX + index + ']');
+            tags.animate({
+                opacity: 0
+            }, 200).delay().animate({
+                opacity: 1
+            }, 200).delay().animate({
+                opacity: 0
+            }, 200).delay().animate({
+                opacity: 1
+            }, 200);
         });
-        // input变化时同步按钮状态(如选择内置正则时)
-        function updateCheckboxFromFlagsInput() {
-            const flags = visualFlagsInput.value;
-            flagCheckboxes.forEach(cb => { cb.checked = flags.includes(cb.value); });
-        }
-        // 修改下拉选择逻辑,选择后同步按钮状态
-        visualRegexPreset.addEventListener('change', function() {
-            const selectedKey = this.value;
-            if (!selectedKey) return;
-            const patternRaw = regexDatabase[selectedKey].patterns.javascript;
-            const match = patternRaw.match(/^\/(.*)\/(\w*)$/);
-            if (match) {
-                visualRegexInput.value = match[1];
-                visualFlagsInput.value = match[2];
+    };
+
+    var _highlight = function (srcText, rstArray) {
+        if (!srcText) {
+            srcBackgroundElm.html('');
+            return;
+        }
+        var hl = [];
+        var preIndex = 0;
+        $.each(rstArray, function (i, item) {
+            if (i === 0) {
+                if (item.index === 0) {
+                    hl.push(_createTag(TAG_MATCHED, item));
+                } else {
+                    hl.push(_createTag(TAG_NOT_MATCHED, {
+                        index: 0,
+                        text: srcText.substring(0, item.index)
+                    }));
+                    hl.push(_createTag(TAG_MATCHED, item));
+                }
             } else {
-                visualRegexInput.value = patternRaw;
-                visualFlagsInput.value = '';
+                preIndex = rstArray[i - 1].index + rstArray[i - 1].text.length;
+                hl.push(_createTag(TAG_NOT_MATCHED, {
+                    index: preIndex,
+                    text: srcText.substring(preIndex, item.index)
+                }));
+                hl.push(_createTag(TAG_MATCHED, item));
             }
-            updateCheckboxFromFlagsInput();
-            if (typeof doVisualTest === 'function') doVisualTest();
         });
-    }
+        srcBackgroundElm.html(hl.join(''));
+        _blinkHighlight();
+    };
 
-    function doVisualTest() {
-        let pattern = visualRegexInput.value.trim();
-        let flags = visualFlagsInput.value.trim();
-        // 自动识别 /pattern/flags
-        if (pattern.startsWith('/') && pattern.lastIndexOf('/') > 0) {
-            const parsed = parsePatternAndFlags(pattern);
-            pattern = parsed.pattern;
-            if (!flags) flags = parsed.flags;
-        }
-        const testText = visualTestText.value;
-        visualErrorMsg.textContent = '';
-        visualErrorMsg.style.visibility = 'hidden';
-        visualResult.innerHTML = '';
-        if (!pattern) {
-            visualErrorMsg.textContent = '请输入正则表达式';
-            visualErrorMsg.style.visibility = 'visible';
-            return;
-        }
-        // 新增:如果测试文本为空,直接返回,不做匹配
-        if (!testText) {
-            visualResult.innerHTML = '';
-            visualErrorMsg.textContent = '';
-            visualErrorMsg.style.visibility = 'hidden';
-            return;
-        }
-        let regex;
-        try {
-            regex = new RegExp(pattern, flags);
-        } catch (e) {
-            visualErrorMsg.textContent = '正则表达式有误:' + e.message;
-            visualErrorMsg.style.visibility = 'visible';
-            return;
-        }
-        // 匹配并高亮
-        const { html, count } = highlightMatchesV2(testText, regex);
-        visualResult.innerHTML = html;
-        // 匹配次数提示
-        if (pattern && testText) {
-            const tip = document.createElement('div');
-            tip.style.margin = '8px 0 0 0';
-            tip.style.color = '#2563eb';
-            tip.style.fontSize = '0.98rem';
-            tip.textContent = `共匹配 ${count} 处`;
-            visualResult.appendChild(tip);
+    var _emptyTable = function (message) {
+        var tbl = ["<table class='table table-bordered table-striped table-condensed table-hover'>"];
+        tbl.push('<tr class="active"><th class="num">序号</th><th>匹配结果</th></tr>');
+        tbl.push('<tr><td colspan="2">' + message + '</td></tr>');
+        tbl.push('</table>');
+        return tbl.join('');
+    };
+
+    var _dealRegMatch = function (e) {
+        if (!srcWrapperElm || !srcElm) return;
+        
+        srcWrapperElm.height(srcElm.height() + 24);
+
+        var regTxt = regElm.val().trim();
+        var srcTxt = srcElm.val().trim();
+        if (!regTxt || !srcTxt) {
+            rstElm.html(_emptyTable('不能匹配'));
+            rstCount.html('0个');
+            _highlight();
+        } else {
+            var reg = _getRegExp(regTxt);
+            if (!reg || !reg instanceof RegExp) {
+                rstElm.html(_emptyTable('正则表达式错误!'));
+                rstCount.html('0个');
+                _highlight();
+                return;
+            }
+            var rst = [];
+            // 用字符串的replace方法来找到匹配目标在元字符串中的准确位置
+            srcTxt.replace(reg, function () {
+                var matchedTxt = arguments[0];
+                var txtIndex = arguments[arguments.length - 2];
+                rst.push({
+                    text: matchedTxt,
+                    index: txtIndex
+                });
+            });
+            if (!rst || !rst.length) {
+                rstElm.html(_emptyTable('不能匹配'));
+                rstCount.html('0个');
+                _highlight();
+            } else {
+                rstElm.html(_buildTable(rst));
+                rstCount.html(rst.length + '个');
+                _highlight(srcElm.val(), rst);
+            }
         }
-    }
+    };
+
+    var _init = function () {
+        regElm = $('#regText');
+        srcElm = $('#srcCode');
+        srcBackgroundElm = $('#srcBackground');
+        srcWrapperElm = $('#srcWrapper');
+        rstElm = $('#rstCode');
+        rstCount = $('#rstCount');
+        regListElm = $('#regList');
 
-    visualTestBtn.addEventListener('click', doVisualTest);
-    // 支持回车快捷测试
-    [visualRegexInput, visualFlagsInput, visualTestText].forEach(el => {
-        el.addEventListener('keydown', function(e) {
-            if (e.key === 'Enter' && (el !== visualTestText || e.ctrlKey || e.metaKey)) {
-                doVisualTest();
-                e.preventDefault();
+        if (!regElm.length) return; // 如果元素不存在,直接返回
+
+        rstElm.html(_emptyTable('暂无输入'));
+
+        // 监听两个输入框的按键、paste、change事件
+        $('#regText,#srcCode').keyup(_dealRegMatch).change(_dealRegMatch)
+            .bind('paste', _dealRegMatch);
+
+        regListElm.change(function (e) {
+            var reg = $(this).val();
+            var regTipElm = $('#regTip');
+            regElm.val(reg);
+            if (!reg) {
+                if (regTipElm.length) regTipElm.hide();
+            } else {
+                if (regTipElm.length) regTipElm.show();
             }
+            _dealRegMatch(); // 触发匹配
         });
-    });
-
-    // textarea内容变化时自动调试
-    visualTestText.addEventListener('input', doVisualTest);
+    };
 
-    // 页面加载时同步一次
-    updateCheckboxFromFlagsInput();
-    loadPatchHotfix();
-});
+    return {
+        init: _init
+    };
+})();