|
@@ -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
|
|
|
+ };
|
|
|
+})();
|