index.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. // 正则表达式数据库
  2. const regexDatabase = {
  3. // 验证类
  4. 'email': {
  5. title: '邮箱验证',
  6. description: '验证电子邮箱地址的合法性,支持@前的各种字符组合,@后必须是域名格式',
  7. patterns: {
  8. javascript: '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/',
  9. python: 'r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"',
  10. php: '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/',
  11. java: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
  12. }
  13. },
  14. 'phone': {
  15. title: '手机号验证',
  16. description: '验证中国大陆手机号码,支持最新号段',
  17. patterns: {
  18. javascript: '/^1[3-9]\\d{9}$/',
  19. python: 'r"^1[3-9]\\d{9}$"',
  20. php: '/^1[3-9]\\d{9}$/',
  21. java: '^1[3-9]\\d{9}$'
  22. }
  23. },
  24. 'tel': {
  25. title: '固定电话验证',
  26. description: '验证固定电话号码,支持区号+号码的格式',
  27. patterns: {
  28. javascript: '/^(0\\d{2,3}-?)?\\d{7,8}$/',
  29. python: 'r"^(0\\d{2,3}-?)?\\d{7,8}$"',
  30. php: '/^(0\\d{2,3}-?)?\\d{7,8}$/',
  31. java: '^(0\\d{2,3}-?)?\\d{7,8}$'
  32. }
  33. },
  34. 'password': {
  35. title: '密码强度验证',
  36. description: '密码必须包含大小写字母、数字和特殊字符,长度8-16位',
  37. patterns: {
  38. javascript: '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$/',
  39. python: 'r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$"',
  40. php: '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$/',
  41. java: '^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[@$!%*?&])[A-Za-z\\d@$!%*?&]{8,16}$'
  42. }
  43. },
  44. 'qq': {
  45. title: 'QQ号验证',
  46. description: '验证QQ号,必须是5-11位数字,首位不能为0',
  47. patterns: {
  48. javascript: '/^[1-9][0-9]{4,10}$/',
  49. python: 'r"^[1-9][0-9]{4,10}$"',
  50. php: '/^[1-9][0-9]{4,10}$/',
  51. java: '^[1-9][0-9]{4,10}$'
  52. }
  53. },
  54. 'postal': {
  55. title: '邮政编码验证',
  56. description: '验证中国邮政编码,6位数字',
  57. patterns: {
  58. javascript: '/^\\d{6}$/',
  59. python: 'r"^\\d{6}$"',
  60. php: '/^\\d{6}$/',
  61. java: '^\\d{6}$'
  62. }
  63. },
  64. 'account': {
  65. title: '账号验证',
  66. description: '验证账号,字母开头,允许5-16位,字母数字下划线组合',
  67. patterns: {
  68. javascript: '/^[a-zA-Z]\\w{4,15}$/',
  69. python: 'r"^[a-zA-Z]\\w{4,15}$"',
  70. php: '/^[a-zA-Z]\\w{4,15}$/',
  71. java: '^[a-zA-Z]\\w{4,15}$'
  72. }
  73. },
  74. 'url': {
  75. title: 'URL验证',
  76. description: '验证URL地址的合法性,支持http、https协议,可选端口、路径、参数、锚点,支持localhost和IP地址',
  77. patterns: {
  78. javascript: '/^(https?:\\/\\/)?((([\\w-]+\\.)+[\\w-]+|localhost|\\d{1,3}(?:\\.\\d{1,3}){3}))(\\:\\d{1,5})?(\\/[^\\s?#]*)?(\\?[^\\s#]*)?(#[^\\s]*)?$/i',
  79. python: 'r"^(https?:\/\/)?((([\w-]+\.)+[\w-]+|localhost|\d{1,3}(?:\.\d{1,3}){3}))(\:\d{1,5})?(\/[^s?#]*)?(\?[^s#]*)?(#[^s]*)?$"',
  80. php: '/^(https?:\\/\\/)?((([\\w-]+\\.)+[\\w-]+|localhost|\\d{1,3}(?:\\.\\d{1,3}){3}))(\\:\\d{1,5})?(\\/[^\\s?#]*)?(\\?[^\\s#]*)?(#[^\\s]*)?$/i',
  81. java: '^(https?:\\/\\/)?((([\\w-]+\\.)+[\\w-]+|localhost|\\d{1,3}(?:\\.\\d{1,3}){3}))(\\:\\d{1,5})?(\\/[^\\s?#]*)?(\\?[^\\s#]*)?(#[^\\s]*)?$'
  82. }
  83. },
  84. 'idcard': {
  85. title: '身份证验证',
  86. description: '验证中国大陆居民身份证号码,支持18位',
  87. patterns: {
  88. 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]$/',
  89. 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-9X]$"',
  90. 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-9X]$/',
  91. 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-9X]$'
  92. }
  93. },
  94. 'ipv4': {
  95. title: 'IPv4地址验证',
  96. description: '验证IPv4地址格式',
  97. patterns: {
  98. 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]?)$/',
  99. python: 'r"^((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]?)$"',
  100. php: '/^((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]?)$/',
  101. java: '^((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]?)$'
  102. }
  103. },
  104. 'date': {
  105. title: '日期验证',
  106. description: '验证日期格式(YYYY-MM-DD)',
  107. patterns: {
  108. javascript: '/^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$/',
  109. python: 'r"^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$"',
  110. php: '/^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$/',
  111. java: '^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$'
  112. }
  113. },
  114. // 提取类
  115. 'html-tag': {
  116. title: 'HTML标签提取',
  117. description: '提取HTML标签及其内容',
  118. patterns: {
  119. javascript: '/<([a-z][a-z0-9]*)[^>]*>.*?<\\/\\1>/gi',
  120. python: 'r"<([a-z][a-z0-9]*)[^>]*>.*?</\\1>"',
  121. php: '/<([a-z][a-z0-9]*)[^>]*>.*?<\\/\\1>/i',
  122. java: '<([a-z][a-z0-9]*)[^>]*>.*?</\\1>'
  123. }
  124. },
  125. 'img-url': {
  126. title: '图片URL提取',
  127. description: '提取HTML中的图片URL',
  128. patterns: {
  129. javascript: '/<img[^>]+src="([^">]+)"/gi',
  130. python: 'r"<img[^>]+src=\\"([^\\">]+)\\""',
  131. php: '/<img[^>]+src="([^">]+)"/i',
  132. java: '<img[^>]+src="([^">]+)"'
  133. }
  134. },
  135. 'chinese': {
  136. title: '中文字符提取',
  137. description: '提取中文字符',
  138. patterns: {
  139. javascript: '/[\\u4e00-\\u9fa5]/g',
  140. python: 'r"[\\u4e00-\\u9fa5]"',
  141. php: '/[\\x{4e00}-\\x{9fa5}]/u',
  142. java: '[\\u4e00-\\u9fa5]'
  143. }
  144. },
  145. 'numbers': {
  146. title: '数字提取',
  147. description: '提取字符串中的数字',
  148. patterns: {
  149. javascript: '/\\d+(\\.\\d+)?/g',
  150. python: 'r"\\d+(\\.\\d+)?"',
  151. php: '/\\d+(\\.\\d+)?/',
  152. java: '\\d+(\\.\\d+)?'
  153. }
  154. },
  155. 'email-extract': {
  156. title: '邮箱地址提取',
  157. description: '提取文本中的邮箱地址',
  158. patterns: {
  159. javascript: '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/g',
  160. python: 'r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"',
  161. php: '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}/',
  162. java: '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}'
  163. }
  164. },
  165. 'color-hex': {
  166. title: '颜色值提取',
  167. description: '提取16进制颜色值,支持3位和6位格式',
  168. patterns: {
  169. javascript: '/#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g',
  170. python: 'r"#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})"',
  171. php: '/#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/i',
  172. java: '#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})'
  173. }
  174. },
  175. 'ip-extract': {
  176. title: 'IP地址提取',
  177. description: '提取IPv4地址',
  178. patterns: {
  179. javascript: '/\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/g',
  180. python: 'r"\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b"',
  181. php: '/\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b/',
  182. java: '\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b'
  183. }
  184. },
  185. // 替换类
  186. 'trim': {
  187. title: '去除首尾空格',
  188. description: '去除字符串首尾的空白字符',
  189. patterns: {
  190. javascript: '/^\\s+|\\s+$/g',
  191. python: 'r"^\\s+|\\s+$"',
  192. php: '/^\\s+|\\s+$/',
  193. java: '^\\s+|\\s+$'
  194. }
  195. },
  196. 'remove-html': {
  197. title: '去除HTML标签',
  198. description: '去除文本中的HTML标签',
  199. patterns: {
  200. javascript: '/<[^>]+>/g',
  201. python: 'r"<[^>]+>"',
  202. php: '/<[^>]+>/',
  203. java: '<[^>]+>'
  204. }
  205. },
  206. 'remove-script': {
  207. title: '去除Script标签',
  208. description: '去除HTML中的script标签及其内容',
  209. patterns: {
  210. javascript: '/<script[^>]*>[\\s\\S]*?<\\/script>/gi',
  211. python: 'r"<script[^>]*>[\\s\\S]*?</script>"',
  212. php: '/<script[^>]*>[\\s\\S]*?<\\/script>/i',
  213. java: '<script[^>]*>[\\s\\S]*?</script>'
  214. }
  215. },
  216. 'remove-space': {
  217. title: '去除多余空格',
  218. description: '去除字符串中的多余空格,保留单个空格',
  219. patterns: {
  220. javascript: '/\\s+/g',
  221. python: 'r"\\s+"',
  222. php: '/\\s+/',
  223. java: '\\s+'
  224. }
  225. },
  226. 'remove-comment': {
  227. title: '去除注释',
  228. description: '去除代码中的单行和多行注释',
  229. patterns: {
  230. javascript: '/(\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/)/gm',
  231. python: 'r"(#.*$)|(\'\'\'[\\s\\S]*?\'\'\')|(\\"\\"\\"[\\s\\S]*?\\"\\"\\"))"',
  232. php: '/(\\/\\/.*$)|(\\/\\*[\\s\\S]*?\\*\\/)/m',
  233. java: '(/\\*([^*]|[\\r\\n]|(\\*+([^*/]|[\\r\\n])))*\\*+/)|(//.*)'
  234. }
  235. },
  236. // 格式化类
  237. 'money': {
  238. title: '金额格式化',
  239. description: '将数字转换为金额格式(每三位加逗号)',
  240. patterns: {
  241. javascript: '/(\\d)(?=(\\d{3})+(?!\\d))/g',
  242. python: 'r"(\\d)(?=(\\d{3})+(?!\\d))"',
  243. php: '/(\\d)(?=(\\d{3})+(?!\\d))/',
  244. java: '(\\d)(?=(\\d{3})+(?!\\d))'
  245. }
  246. },
  247. 'phone-format': {
  248. title: '手机号格式化',
  249. description: '将手机号格式化为 xxx-xxxx-xxxx',
  250. patterns: {
  251. javascript: '/(\\d{3})(\\d{4})(\\d{4})/',
  252. python: 'r"(\\d{3})(\\d{4})(\\d{4})"',
  253. php: '/(\\d{3})(\\d{4})(\\d{4})/',
  254. java: '(\\d{3})(\\d{4})(\\d{4})'
  255. }
  256. },
  257. 'date-format': {
  258. title: '日期格式化',
  259. description: '将日期字符串格式化为指定格式',
  260. patterns: {
  261. javascript: '/(\\d{4})-(\\d{2})-(\\d{2})/',
  262. python: 'r"(\\d{4})-(\\d{2})-(\\d{2})"',
  263. php: '/(\\d{4})-(\\d{2})-(\\d{2})/',
  264. java: '(\\d{4})-(\\d{2})-(\\d{2})'
  265. }
  266. },
  267. 'card-format': {
  268. title: '银行卡格式化',
  269. description: '将银行卡号每4位添加一个空格',
  270. patterns: {
  271. javascript: '/(\\d{4})(?=\\d)/g',
  272. python: 'r"(\\d{4})(?=\\d)"',
  273. php: '/(\\d{4})(?=\\d)/',
  274. java: '(\\d{4})(?=\\d)'
  275. }
  276. },
  277. 'idcard-format': {
  278. title: '身份证格式化',
  279. description: '将身份证号码按6-8-4格式分组',
  280. patterns: {
  281. javascript: '/(^\\d{6})(\\d{8})(\\d{4})/g',
  282. python: 'r"(^\\d{6})(\\d{8})(\\d{4})"',
  283. php: '/(^\\d{6})(\\d{8})(\\d{4})/',
  284. java: '(^\\d{6})(\\d{8})(\\d{4})'
  285. }
  286. },
  287. // 特殊字符类
  288. 'emoji': {
  289. title: 'Emoji表情',
  290. description: '匹配Unicode emoji表情符号',
  291. patterns: {
  292. javascript: '/[\\u{1F300}-\\u{1F9FF}]/gu',
  293. python: 'r"[\\U0001F300-\\U0001F9FF]"',
  294. php: '/[\\x{1F300}-\\x{1F9FF}]/u',
  295. java: '[\\uD83C\\uDF00-\\uD83D\\uDDFF]'
  296. }
  297. },
  298. 'special-char': {
  299. title: '特殊字符',
  300. description: '匹配常见特殊字符',
  301. patterns: {
  302. javascript: '/[`~!@#$%^&*()_\\-+=<>?:"{}|,.\\/;\'\\[\\]·~!@#¥%……&*()——\\-+={}|《》?:""【】、;\',。、]/g',
  303. python: 'r"[`~!@#$%^&*()_\\-+=<>?:\\"{}|,.\\/;\\\'\\[\\]·~!@#¥%……&*()——\\-+={}|《》?:""【】、;\\\',。、]"',
  304. php: '/[`~!@#$%^&*()_\\-+=<>?:"{}|,.\\/;\'\\[\\]·~!@#¥%……&*()——\\-+={}|《》?:""【】、;\',。、]/',
  305. java: '[`~!@#$%^&*()_\\-+=<>?:"{}|,.\\/;\'\\[\\]·~!@#¥%……&*()——\\-+={}|《》?:""【】、;\',。、]'
  306. }
  307. },
  308. 'invisible-char': {
  309. title: '不可见字符',
  310. description: '匹配不可见字符(空格、制表符、换行符等)',
  311. patterns: {
  312. javascript: '/[\\s\\u200B-\\u200D\\uFEFF]/g',
  313. python: 'r"[\\s\\u200B-\\u200D\\uFEFF]"',
  314. php: '/[\\s\\x{200B}-\\x{200D}\\x{FEFF}]/u',
  315. java: '[\\s\\u200B-\\u200D\\uFEFF]'
  316. }
  317. },
  318. // 编程相关
  319. 'variable': {
  320. title: '变量命名',
  321. description: '验证合法的变量名(字母、数字、下划线,字母开头)',
  322. patterns: {
  323. javascript: '/^[a-zA-Z_$][a-zA-Z0-9_$]*$/',
  324. python: 'r"^[a-zA-Z_][a-zA-Z0-9_]*$"',
  325. php: '/^[a-zA-Z_][a-zA-Z0-9_]*$/',
  326. java: '^[a-zA-Z_$][a-zA-Z0-9_$]*$'
  327. }
  328. },
  329. 'function': {
  330. title: '函数声明',
  331. description: '匹配函数声明语句',
  332. patterns: {
  333. javascript: '/function\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\([^)]*\\)\\s*{/',
  334. python: 'r"def\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\([^)]*\\)\\s*:"',
  335. php: '/function\\s+([a-zA-Z_][a-zA-Z0-9_]*)\\s*\\([^)]*\\)\\s*{/',
  336. java: '(public|private|protected|static|\\s) +[\\w\\<\\>\\[\\]]+\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\\s*\\([^)]*\\)\\s*\\{'
  337. }
  338. },
  339. 'json': {
  340. title: 'JSON格式',
  341. description: '验证JSON字符串格式',
  342. patterns: {
  343. javascript: '/^\\s*({[\\s\\S]*}|\\[[\\s\\S]*\\])\\s*$/',
  344. python: 'r"^\\s*({[\\s\\S]*}|\\[[\\s\\S]*\\])\\s*$"',
  345. php: '/^\\s*({[\\s\\S]*}|\\[[\\s\\S]*\\])\\s*$/',
  346. java: '^\\s*({[\\s\\S]*}|\\[[\\s\\S]*\\])\\s*$'
  347. }
  348. },
  349. 'xml': {
  350. title: 'XML标签',
  351. description: '匹配XML标签',
  352. patterns: {
  353. javascript: '/<\\/?([a-z][\\w-]*)(?:\\s+[^>]*)?>/gi',
  354. python: 'r"<\\/?([a-z][\\w-]*)(?:\\s+[^>]*)?>)"',
  355. php: '/<\\/?([a-z][\\w-]*)(?:\\s+[^>]*)?>/i',
  356. java: '<\\/?([a-z][\\w-]*)(?:\\s+[^>]*)?>'
  357. }
  358. },
  359. 'css': {
  360. title: 'CSS选择器',
  361. description: '匹配CSS选择器',
  362. patterns: {
  363. javascript: '/[.#]?[a-zA-Z_-][\\w-]*(?:\\[[^\\]]+\\])?(?:\\.[a-zA-Z_-][\\w-]*)*/',
  364. python: 'r"[.#]?[a-zA-Z_-][\\w-]*(?:\\[[^\\]]+\\])?(?:\\.[a-zA-Z_-][\\w-]*)*"',
  365. php: '/[.#]?[a-zA-Z_-][\\w-]*(?:\\[[^\\]]+\\])?(?:\\.[a-zA-Z_-][\\w-]*)*/',
  366. java: '[.#]?[a-zA-Z_-][\\w-]*(?:\\[[^\\]]+\\])?(?:\\.[a-zA-Z_-][\\w-]*)*'
  367. }
  368. },
  369. // 数字验证类
  370. 'number': {
  371. title: '数字验证',
  372. description: '验证是否为纯数字',
  373. patterns: {
  374. javascript: '/^\d+$/',
  375. python: 'r"^\d+$"',
  376. php: '/^\d+$/',
  377. java: '^\\d+$'
  378. }
  379. },
  380. 'number-n-digits': {
  381. title: 'n位数字验证',
  382. description: '验证是否为n位数字(示例为4位)',
  383. patterns: {
  384. javascript: '/^\d{4}$/',
  385. python: 'r"^\d{4}$"',
  386. php: '/^\d{4}$/',
  387. java: '^\\d{4}$'
  388. }
  389. },
  390. 'number-min-n-digits': {
  391. title: '至少n位数字验证',
  392. description: '验证是否至少包含n位数字(示例为6位)',
  393. patterns: {
  394. javascript: '/^\d{6,}$/',
  395. python: 'r"^\d{6,}$"',
  396. php: '/^\d{6,}$/',
  397. java: '^\\d{6,}$'
  398. }
  399. },
  400. 'number-range-digits': {
  401. title: '数字位数范围验证',
  402. description: '验证数字位数是否在指定范围内(示例为6-18位)',
  403. patterns: {
  404. javascript: '/^\d{6,18}$/',
  405. python: 'r"^\d{6,18}$"',
  406. php: '/^\d{6,18}$/',
  407. java: '^\\d{6,18}$'
  408. }
  409. },
  410. 'decimal': {
  411. title: '小数验证',
  412. description: '验证是否为小数',
  413. patterns: {
  414. javascript: '/^\d+\.\d+$/',
  415. python: 'r"^\d+\.\d+$"',
  416. php: '/^\d+\.\d+$/',
  417. java: '^\\d+\\.\\d+$'
  418. }
  419. },
  420. 'integer': {
  421. title: '整数验证',
  422. description: '验证是否为整数(包括正负整数)',
  423. patterns: {
  424. javascript: '/^-?\\d+$/',
  425. python: 'r"^-?\\d+$"',
  426. php: '/^-?\\d+$/',
  427. java: '^-?\\d+$'
  428. }
  429. },
  430. // 文本格式类
  431. 'chinese-name': {
  432. title: '中文姓名验证',
  433. description: '验证中文姓名(2-6个汉字)',
  434. patterns: {
  435. javascript: '/^[\\u4e00-\\u9fa5]{2,6}$/',
  436. python: 'r"^[\\u4e00-\\u9fa5]{2,6}$"',
  437. php: '/^[\\x{4e00}-\\x{9fa5}]{2,6}$/u',
  438. java: '^[\\u4e00-\\u9fa5]{2,6}$'
  439. }
  440. },
  441. 'english-name': {
  442. title: '英文姓名验证',
  443. description: '验证英文姓名(支持空格和点号)',
  444. patterns: {
  445. javascript: '/^[a-zA-Z][a-zA-Z\\s\\.]{0,58}[a-zA-Z]$/',
  446. python: 'r"^[a-zA-Z][a-zA-Z\\s\\.]{0,58}[a-zA-Z]$"',
  447. php: '/^[a-zA-Z][a-zA-Z\\s\\.]{0,58}[a-zA-Z]$/',
  448. java: '^[a-zA-Z][a-zA-Z\\s\\.]{0,58}[a-zA-Z]$'
  449. }
  450. },
  451. 'username': {
  452. title: '用户名验证',
  453. description: '验证用户名(字母开头,允许5-16字节,允许字母数字下划线)',
  454. patterns: {
  455. javascript: '/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/',
  456. python: 'r"^[a-zA-Z][a-zA-Z0-9_]{4,15}$"',
  457. php: '/^[a-zA-Z][a-zA-Z0-9_]{4,15}$/',
  458. java: '^[a-zA-Z][a-zA-Z0-9_]{4,15}$'
  459. }
  460. },
  461. 'password-strong': {
  462. title: '强密码验证',
  463. description: '验证密码强度(必须包含大小写字母和数字,可以包含特殊字符,长度8-16)',
  464. patterns: {
  465. javascript: '/^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9!@#$%^&*]{8,16}$/',
  466. python: 'r"^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9!@#$%^&*]{8,16}$"',
  467. php: '/^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9!@#$%^&*]{8,16}$/',
  468. java: '^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9!@#$%^&*]{8,16}$'
  469. }
  470. },
  471. // 特殊格式类
  472. 'mac-address': {
  473. title: 'MAC地址验证',
  474. description: '验证MAC地址格式',
  475. patterns: {
  476. javascript: '/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/',
  477. python: 'r"^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"',
  478. php: '/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/',
  479. java: '^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$'
  480. }
  481. },
  482. 'hex-color': {
  483. title: '16进制颜色验证',
  484. description: '验证16进制颜色代码',
  485. patterns: {
  486. javascript: '/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/',
  487. python: 'r"^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$"',
  488. php: '/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/',
  489. java: '^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$'
  490. }
  491. },
  492. 'version-number': {
  493. title: '版本号验证',
  494. description: '验证版本号格式(x.y.z)',
  495. patterns: {
  496. javascript: '/^\\d+\\.\\d+\\.\\d+$/',
  497. python: 'r"^\\d+\\.\\d+\\.\\d+$"',
  498. php: '/^\\d+\\.\\d+\\.\\d+$/',
  499. java: '^\\d+\\.\\d+\\.\\d+$'
  500. }
  501. }
  502. };
  503. // 初始化事件监听
  504. document.addEventListener('DOMContentLoaded', () => {
  505. const modal = document.getElementById('regexModal');
  506. const closeBtn = document.querySelector('.close');
  507. const regexItems = document.querySelectorAll('.regex-item');
  508. const copyButtons = document.querySelectorAll('.copy-btn');
  509. // 点击正则表达式项显示模态框
  510. regexItems.forEach(item => {
  511. item.addEventListener('click', () => {
  512. const regexId = item.getAttribute('data-regex-id');
  513. const regexData = regexDatabase[regexId];
  514. if (regexData) {
  515. document.getElementById('modalTitle').textContent = regexData.title;
  516. document.getElementById('jsRegex').textContent = regexData.patterns.javascript;
  517. document.getElementById('pythonRegex').textContent = regexData.patterns.python;
  518. document.getElementById('phpRegex').textContent = regexData.patterns.php;
  519. document.getElementById('javaRegex').textContent = regexData.patterns.java;
  520. document.getElementById('regexDescription').textContent = regexData.description;
  521. modal.style.display = 'block';
  522. }
  523. });
  524. });
  525. // 关闭模态框
  526. closeBtn.addEventListener('click', () => {
  527. modal.style.display = 'none';
  528. });
  529. // 点击模态框外部关闭
  530. window.addEventListener('click', (event) => {
  531. if (event.target === modal) {
  532. modal.style.display = 'none';
  533. }
  534. });
  535. // 点击模态框外部关闭
  536. document.getElementById('donate-link').addEventListener('click', (event) => {
  537. event.preventDefault();
  538. event.stopPropagation();
  539. chrome.runtime.sendMessage({
  540. type: 'fh-dynamic-any-thing',
  541. thing: 'open-donate-modal',
  542. params: { toolName: 'regexp' }
  543. });
  544. return false;
  545. });
  546. document.getElementById('other-tools').addEventListener('click', (event) => {
  547. event.preventDefault();
  548. event.stopPropagation();
  549. chrome.runtime.openOptionsPage();
  550. return false;
  551. });
  552. // 复制按钮功能
  553. copyButtons.forEach(button => {
  554. button.addEventListener('click', () => {
  555. const targetId = button.getAttribute('data-target');
  556. const codeElement = document.getElementById(targetId);
  557. const text = codeElement.textContent;
  558. navigator.clipboard.writeText(text).then(() => {
  559. const originalText = button.textContent;
  560. button.textContent = '已复制!';
  561. button.style.backgroundColor = '#27ae60';
  562. setTimeout(() => {
  563. button.textContent = originalText;
  564. button.style.backgroundColor = '#3498db';
  565. }, 2000);
  566. }).catch(err => {
  567. console.error('复制失败:', err);
  568. button.textContent = '复制失败';
  569. button.style.backgroundColor = '#e74c3c';
  570. setTimeout(() => {
  571. button.textContent = '复制';
  572. button.style.backgroundColor = '#3498db';
  573. }, 2000);
  574. });
  575. });
  576. });
  577. });
  578. // 搜索功能实现
  579. document.addEventListener('DOMContentLoaded', function() {
  580. const searchInput = document.getElementById('regexSearch');
  581. const regexItems = document.querySelectorAll('.regex-item');
  582. searchInput.addEventListener('input', function(e) {
  583. const searchTerm = e.target.value.toLowerCase().trim();
  584. regexItems.forEach(item => {
  585. const text = item.textContent.toLowerCase();
  586. const match = text.includes(searchTerm);
  587. item.classList.toggle('hidden', !match);
  588. item.classList.toggle('highlight', match && searchTerm !== '');
  589. // 处理分类标题的显示/隐藏
  590. const category = item.closest('.category');
  591. const visibleItems = category.querySelectorAll('.regex-item:not(.hidden)');
  592. category.style.display = visibleItems.length > 0 ? 'block' : 'none';
  593. });
  594. });
  595. // 添加清空搜索框的快捷键(ESC)
  596. searchInput.addEventListener('keydown', function(e) {
  597. if (e.key === 'Escape') {
  598. searchInput.value = '';
  599. // 触发 input 事件以更新显示
  600. searchInput.dispatchEvent(new Event('input'));
  601. }
  602. });
  603. });
  604. // 正则可视化调试区域逻辑(升级版)
  605. function parsePatternAndFlags(input) {
  606. // 自动识别 /pattern/flags 或 pattern
  607. const match = input.match(/^\s*\/(.*)\/(\w*)\s*$/);
  608. if (match) {
  609. return { pattern: match[1], flags: match[2] };
  610. }
  611. return { pattern: input, flags: '' };
  612. }
  613. function highlightMatchesV2(text, regex) {
  614. if (!text) return '';
  615. let lastIndex = 0;
  616. let result = '';
  617. let match;
  618. let hasMatch = false;
  619. regex.lastIndex = 0;
  620. let count = 0;
  621. while ((match = regex.exec(text)) !== null) {
  622. hasMatch = true;
  623. count++;
  624. // 防止死循环
  625. if (match[0] === '') {
  626. result += text.slice(lastIndex);
  627. break;
  628. }
  629. result += text.slice(lastIndex, match.index);
  630. // 高亮主匹配内容
  631. let main = '<span class="visual-match">' + match[0] + '</span>';
  632. // 如果有分组,显示分组高亮
  633. if (match.length > 1) {
  634. let groupHtml = '';
  635. for (let i = 1; i < match.length; i++) {
  636. if (typeof match[i] === 'string') {
  637. groupHtml += `<span class="visual-group">$${i}: ${match[i]}</span> `;
  638. }
  639. }
  640. main += '<span class="visual-group-list">' + groupHtml.trim() + '</span>';
  641. }
  642. result += main;
  643. lastIndex = match.index + match[0].length;
  644. if (!regex.global) break;
  645. }
  646. result += text.slice(lastIndex);
  647. return { html: hasMatch ? result : text, count };
  648. }
  649. function loadPatchHotfix() {
  650. // 页面加载时自动获取并注入页面的补丁
  651. chrome.runtime.sendMessage({
  652. type: 'fh-dynamic-any-thing',
  653. thing: 'fh-get-tool-patch',
  654. toolName: 'regexp'
  655. }, patch => {
  656. if (patch) {
  657. if (patch.css) {
  658. const style = document.createElement('style');
  659. style.textContent = patch.css;
  660. document.head.appendChild(style);
  661. }
  662. if (patch.js) {
  663. try {
  664. if (window.evalCore && window.evalCore.getEvalInstance) {
  665. window.evalCore.getEvalInstance(window)(patch.js);
  666. }
  667. } catch (e) {
  668. console.error('regexp补丁JS执行失败', e);
  669. }
  670. }
  671. }
  672. });
  673. }
  674. document.addEventListener('DOMContentLoaded', function() {
  675. // 可视化调试相关
  676. const visualRegexPreset = document.getElementById('visualRegexPreset');
  677. const visualRegexInput = document.getElementById('visualRegex');
  678. const visualFlagsInput = document.getElementById('visualFlags');
  679. const visualTestText = document.getElementById('visualTestText');
  680. const visualTestBtn = document.getElementById('visualTestBtn');
  681. const visualResult = document.getElementById('visualResult');
  682. const visualErrorMsg = document.getElementById('visualErrorMsg');
  683. // 动态填充下拉框
  684. if (visualRegexPreset) {
  685. for (const key in regexDatabase) {
  686. if (regexDatabase[key].patterns && regexDatabase[key].patterns.javascript) {
  687. const option = document.createElement('option');
  688. option.value = key;
  689. option.textContent = regexDatabase[key].title;
  690. option.setAttribute('data-regex', regexDatabase[key].patterns.javascript);
  691. visualRegexPreset.appendChild(option);
  692. }
  693. }
  694. // 标志按钮组与隐藏input联动
  695. const flagCheckboxes = document.querySelectorAll('.visual-flags-group input[type="checkbox"]');
  696. function updateFlagsInputFromCheckbox() {
  697. let flags = '';
  698. flagCheckboxes.forEach(cb => { if (cb.checked) flags += cb.value; });
  699. visualFlagsInput.value = flags;
  700. doVisualTest();
  701. }
  702. flagCheckboxes.forEach(cb => {
  703. cb.addEventListener('change', updateFlagsInputFromCheckbox);
  704. });
  705. // input变化时同步按钮状态(如选择内置正则时)
  706. function updateCheckboxFromFlagsInput() {
  707. const flags = visualFlagsInput.value;
  708. flagCheckboxes.forEach(cb => { cb.checked = flags.includes(cb.value); });
  709. }
  710. // 修改下拉选择逻辑,选择后同步按钮状态
  711. visualRegexPreset.addEventListener('change', function() {
  712. const selectedKey = this.value;
  713. if (!selectedKey) return;
  714. const patternRaw = regexDatabase[selectedKey].patterns.javascript;
  715. const match = patternRaw.match(/^\/(.*)\/(\w*)$/);
  716. if (match) {
  717. visualRegexInput.value = match[1];
  718. visualFlagsInput.value = match[2];
  719. } else {
  720. visualRegexInput.value = patternRaw;
  721. visualFlagsInput.value = '';
  722. }
  723. updateCheckboxFromFlagsInput();
  724. if (typeof doVisualTest === 'function') doVisualTest();
  725. });
  726. }
  727. function doVisualTest() {
  728. let pattern = visualRegexInput.value.trim();
  729. let flags = visualFlagsInput.value.trim();
  730. // 自动识别 /pattern/flags
  731. if (pattern.startsWith('/') && pattern.lastIndexOf('/') > 0) {
  732. const parsed = parsePatternAndFlags(pattern);
  733. pattern = parsed.pattern;
  734. if (!flags) flags = parsed.flags;
  735. }
  736. const testText = visualTestText.value;
  737. visualErrorMsg.textContent = '';
  738. visualErrorMsg.style.visibility = 'hidden';
  739. visualResult.innerHTML = '';
  740. if (!pattern) {
  741. visualErrorMsg.textContent = '请输入正则表达式';
  742. visualErrorMsg.style.visibility = 'visible';
  743. return;
  744. }
  745. // 新增:如果测试文本为空,直接返回,不做匹配
  746. if (!testText) {
  747. visualResult.innerHTML = '';
  748. visualErrorMsg.textContent = '';
  749. visualErrorMsg.style.visibility = 'hidden';
  750. return;
  751. }
  752. let regex;
  753. try {
  754. regex = new RegExp(pattern, flags);
  755. } catch (e) {
  756. visualErrorMsg.textContent = '正则表达式有误:' + e.message;
  757. visualErrorMsg.style.visibility = 'visible';
  758. return;
  759. }
  760. // 匹配并高亮
  761. const { html, count } = highlightMatchesV2(testText, regex);
  762. visualResult.innerHTML = html;
  763. // 匹配次数提示
  764. if (pattern && testText) {
  765. const tip = document.createElement('div');
  766. tip.style.margin = '8px 0 0 0';
  767. tip.style.color = '#2563eb';
  768. tip.style.fontSize = '0.98rem';
  769. tip.textContent = `共匹配 ${count} 处`;
  770. visualResult.appendChild(tip);
  771. }
  772. }
  773. visualTestBtn.addEventListener('click', doVisualTest);
  774. // 支持回车快捷测试
  775. [visualRegexInput, visualFlagsInput, visualTestText].forEach(el => {
  776. el.addEventListener('keydown', function(e) {
  777. if (e.key === 'Enter' && (el !== visualTestText || e.ctrlKey || e.metaKey)) {
  778. doVisualTest();
  779. e.preventDefault();
  780. }
  781. });
  782. });
  783. // textarea内容变化时自动调试
  784. visualTestText.addEventListener('input', doVisualTest);
  785. // 页面加载时同步一次
  786. updateCheckboxFromFlagsInput();
  787. loadPatchHotfix();
  788. });