it编程 > 编程语言 > 正则表达式

前端正则表达式表单验证与字符串处理高频场景实战合集

42人参与 2026-02-28 正则表达式

1. 正则表达式基础回顾

1.1 基本概念

正则表达式(regular expression)是用于匹配字符串中字符组合的模式。在javascript中,我们可以使用两种方式创建正则表达式:

// 字面量方式
const regex1 = /abc/;

// 构造函数方式
const regex2 = new regexp('abc');

1.2 常用元字符

元字符描述示例
.匹配除换行符外的任意字符/a.c/ 匹配 “abc”, “aac”
^匹配字符串的开始/^abc/ 匹配以abc开头的字符串
$匹配字符串的结束/abc$/ 匹配以abc结尾的字符串
*匹配前面的子表达式零次或多次/ab*c/ 匹配 “ac”, “abc”, “abbc”
+匹配前面的子表达式一次或多次/ab+c/ 匹配 “abc”, “abbc”
?匹配前面的子表达式零次或一次/ab?c/ 匹配 “ac”, “abc”
[]字符集合,匹配其中任意一个字符/[abc]/ 匹配 “a”, “b”, “c”
\d匹配数字,等价于[0-9]/\d+/ 匹配一个或多个数字
\w匹配字母、数字、下划线/\w+/ 匹配单词字符
\s匹配空白字符/\s+/ 匹配一个或多个空白

2. 表单验证场景实战

2.1 邮箱验证

邮箱验证是前端开发中最常见的需求之一。一个完善的邮箱正则应该考虑各种格式:

/**
 * 邮箱验证 - 基础版本
 * 适合大多数场景
 */
function validateemailbasic(email) {
    const regex = /^[\w.-]+@[\w.-]+\.\w+$/;
    return regex.test(email);
}

/**
 * 邮箱验证 - 严格版本
 * 符合rfc 5322标准的大部分规则
 */
function validateemailstrict(email) {
    const regex = /^[a-za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-za-z0-9](?:[a-za-z0-9-]{0,61}[a-za-z0-9])?(?:\.[a-za-z0-9](?:[a-za-z0-9-]{0,61}[a-za-z0-9])?)*$/;
    return regex.test(email);
}

/**
 * 邮箱验证 - 实用版本
 * 平衡准确性和性能
 */
function validateemailpractical(email) {
    const regex = /^[a-za-z0-9._%+-]+@[a-za-z0-9.-]+\.[a-za-z]{2,}$/;
    return regex.test(email);
}

// 测试用例
console.log(validateemailbasic('user@example.com')); // true
console.log(validateemailbasic('user.name@example.com')); // true
console.log(validateemailbasic('user@example.co.uk')); // true
console.log(validateemailbasic('invalid.email')); // false

2.2 手机号验证

不同国家的手机号格式不同,这里以中国手机号为例:

/**
 * 中国手机号验证
 * 支持最新的号段
 */
function validatechinesephone(phone) {
    const regex = /^1[3-9]\d{9}$/;
    return regex.test(phone);
}

/**
 * 带区号的手机号验证
 */
function validatephonewithareacode(phone) {
    const regex = /^(?:\+86)?1[3-9]\d{9}$/;
    return regex.test(phone);
}

/**
 * 固话号码验证
 */
function validatelandline(phone) {
    const regex = /^(?:0[1-9]\d{1,2}-)?[2-8]\d{6,7}$/;
    return regex.test(phone);
}

// 测试用例
console.log(validatechinesephone('13800138000')); // true
console.log(validatechinesephone('+8613800138000')); // false
console.log(validatephonewithareacode('+8613800138000')); // true
console.log(validatelandline('010-12345678')); // true

2.3 身份证号验证

中国大陆的身份证号有严格的校验规则:

/**
 * 身份证号验证
 * 包含15位和18位身份证号的验证
 */
function validateidcard(idcard) {
    // 基本格式验证
    const regex15 = /^[1-9]\d{7}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}$/;
    const regex18 = /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dx]$/;
    
    if (idcard.length === 15) {
        return regex15.test(idcard);
    } else if (idcard.length === 18) {
        if (!regex18.test(idcard)) return false;
        
        // 校验码验证
        const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        const checkcodes = ['1', '0', 'x', '9', '8', '7', '6', '5', '4', '3', '2'];
        
        let sum = 0;
        for (let i = 0; i < 17; i++) {
            sum += parseint(idcard[i]) * weights[i];
        }
        
        const checkcode = checkcodes[sum % 11];
        return idcard[17].touppercase() === checkcode;
    }
    
    return false;
}

// 测试用例
console.log(validateidcard('11010519900307283x')); // true
console.log(validateidcard('110105900307283')); // true
console.log(validateidcard('123456789012345')); // false

2.4 密码强度验证

密码强度验证通常需要满足多个条件:

/**
 * 密码强度验证 - 基础版本
 */
function validatepasswordbasic(password) {
    // 至少8位,包含字母和数字
    const regex = /^(?=.*[a-za-z])(?=.*\d)[a-za-z\d@$!%*#?&]{8,}$/;
    return regex.test(password);
}

/**
 * 密码强度验证 - 中级版本
 * 必须包含大小写字母、数字、特殊字符中的至少3种
 */
function validatepasswordmedium(password) {
    const regex = /^(?=.*[a-z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[a-za-z\d@$!%*?&]{8,}$/;
    return regex.test(password);
}

/**
 * 密码强度验证 - 高级版本
 * 自定义规则,可配置不同强度等级
 */
function validatepasswordadvanced(password, options = {}) {
    const {
        minlength = 8,
        maxlength = 20,
        requireuppercase = true,
        requirelowercase = true,
        requirenumbers = true,
        requirespecialchars = false,
        specialchars = '@$!%*?&'
    } = options;

    if (password.length < minlength || password.length > maxlength) {
        return false;
    }

    let pattern = '^';
    
    if (requirelowercase) pattern += '(?=.*[a-z])';
    if (requireuppercase) pattern += '(?=.*[a-z])';
    if (requirenumbers) pattern += '(?=.*\\d)';
    if (requirespecialchars) pattern += `(?=.*[${specialchars.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}])`;
    
    pattern += `[a-za-z\\d${specialchars.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}]{${minlength},${maxlength}}$`;
    
    const regex = new regexp(pattern);
    return regex.test(password);
}

// 测试用例
console.log(validatepasswordbasic('password123')); // true
console.log(validatepasswordmedium('password123!')); // true
console.log(validatepasswordadvanced('mypassword', {requireuppercase: false})); // true

2.5 url验证

url格式验证需要考虑多种协议和格式:

/**
 * url验证 - 基础版本
 */
function validateurlbasic(url) {
    const regex = /^https?:\/\/(www\.)?[-a-za-z0-9@:%._\+~#=]{1,256}\.[a-za-z0-9()]{1,6}\b([-a-za-z0-9()@:%_\+.~#?&//=]*)$/;
    return regex.test(url);
}

/**
 * url验证 - 完整版本
 * 支持更多协议和格式
 */
function validateurlcomplete(url) {
    const regex = /^(https?|ftp):\/\/((([\w-]+\.)+[\w-]+)|localhost)(:[0-9]+)?(\/[\w- .\/?%&=]*)?$/;
    return regex.test(url);
}

/**
 * 提取url中的域名
 */
function extractdomain(url) {
    const regex = /^(?:https?:\/\/)?(?:www\.)?([^\/]+)/;
    const match = url.match(regex);
    return match ? match[1] : null;
}

// 测试用例
console.log(validateurlbasic('https://www.example.com')); // true
console.log(validateurlbasic('http://example.com/path/to/page')); // true
console.log(extractdomain('https://www.example.com/path')); // www.example.com

2.6 ip地址验证

ip地址验证包括ipv4和ipv6:

/**
 * ipv4地址验证
 */
function validateipv4(ip) {
    const regex = /^(?:(?: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]?)$/;
    return regex.test(ip);
}

/**
 * ipv6地址验证
 */
function validateipv6(ip) {
    const regex = /^(?:[0-9a-fa-f]{1,4}:){7}[0-9a-fa-f]{1,4}$|^::1$|^::$/;
    return regex.test(ip);
}

/**
 * 通用ip地址验证
 */
function validateip(ip) {
    return validateipv4(ip) || validateipv6(ip);
}

// 测试用例
console.log(validateipv4('192.168.1.1')); // true
console.log(validateipv4('256.1.1.1')); // false
console.log(validateipv6('2001:0db8:85a3:0000:0000:8a2e:0370:7334')); // true

3. 字符串处理高频场景

3.1 html标签清理

在处理富文本内容时,经常需要清理html标签:

/**
 * 移除所有html标签
 */
function removeallhtmltags(html) {
    return html.replace(/<[^>]*>/g, '');
}

/**
 * 移除指定html标签
 */
function removespecifichtmltags(html, tags) {
    const tagpattern = tags.map(tag => `<${tag}[^>]*>|<\\/${tag}>`).join('|');
    const regex = new regexp(tagpattern, 'gi');
    return html.replace(regex, '');
}

/**
 * 保留指定html标签,移除其他标签
 */
function keepspecifichtmltags(html, allowedtags) {
    const allowedpattern = allowedtags.map(tag => `<${tag}[^>]*>|<\\/${tag}>`).join('|');
    const alltagspattern = /<[^>]*>/g;
    
    return html.replace(alltagspattern, (match) => {
        const regex = new regexp(allowedpattern, 'i');
        return regex.test(match) ? match : '';
    });
}

/**
 * 转义html特殊字符
 */
function escapehtml(html) {
    const escapemap = {
        '&': '&',
        '<': '<',
        '>': '>',
        '"': '&quot;',
        "'": '&#39;'
    };
    
    return html.replace(/[&<>"']/g, (match) => escapemap[match]);
}

// 测试用例
const htmlcontent = '<div><p>hello <script>alert("xss")</script>world!</p></div>';
console.log(removeallhtmltags(htmlcontent)); // "hello world!"
console.log(removespecifichtmltags(htmlcontent, ['script'])); // "<div><p>hello world!</p></div>"
console.log(keepspecifichtmltags(htmlcontent, ['p'])); // "<p>hello world!</p>"

3.2 特殊字符过滤

处理用户输入时,经常需要过滤特殊字符:

/**
 * 移除非字母数字字符
 */
function removenonalphanumeric(str) {
    return str.replace(/[^a-za-z0-9]/g, '');
}

/**
 * 移除非中文字符
 */
function removenonchinese(str) {
    return str.replace(/[^\u4e00-\u9fa5]/g, '');
}

/**
 * 移除非ascii字符
 */
function removenonascii(str) {
    return str.replace(/[^\x00-\x7f]/g, '');
}

/**
 * 自定义字符过滤
 */
function filtercustomcharacters(str, allowedchars) {
    const pattern = `[^${allowedchars.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}]`;
    const regex = new regexp(pattern, 'g');
    return str.replace(regex, '');
}

/**
 * 移除非打印字符
 */
function removenonprintable(str) {
    return str.replace(/[\x00-\x1f\x7f-\x9f]/g, '');
}

// 测试用例
console.log(removenonalphanumeric('hello, 世界! 123')); // "hello123"
console.log(removenonchinese('hello, 世界! 123')); // "世界"
console.log(filtercustomcharacters('hello123!@#', 'a-za-z')); // "hello"

3.3 数字格式化

数字格式化在金融、电商等场景中非常常见:

/**
 * 千位分隔符格式化
 */
function formatnumberwithcommas(number) {
    return number.tostring().replace(/\b(?=(\d{3})+(?!\d))/g, ',');
}

/**
 * 货币格式化
 */
function formatcurrency(amount, currency = 'cny') {
    const formatted = formatnumberwithcommas(amount);
    const symbols = {
        'cny': '¥',
        'usd': '$',
        'eur': '€',
        'gbp': '£'
    };
    return `${symbols[currency] || ''}${formatted}`;
}

/**
 * 提取字符串中的数字
 */
function extractnumbers(str) {
    const matches = str.match(/\d+(?:\.\d+)?/g);
    return matches ? matches.map(number) : [];
}

/**
 * 科学计数法转普通数字
 */
function scientifictodecimal(numstr) {
    const match = numstr.match(/^(\d+(?:\.\d+)?)[ee]([+-]?\d+)$/);
    if (!match) return numstr;
    
    const [, digits, exponent] = match;
    const exp = parseint(exponent, 10);
    const [integer, decimal = ''] = digits.split('.');
    
    if (exp >= 0) {
        return integer + decimal.padend(exp + decimal.length, '0');
    } else {
        const totallength = integer.length + math.abs(exp);
        const result = (integer + decimal).padstart(totallength, '0');
        return '0.' + result.slice(0, totallength);
    }
}

// 测试用例
console.log(formatnumberwithcommas(1234567)); // "1,234,567"
console.log(formatcurrency(1234567, 'usd')); // "$1,234,567"
console.log(extractnumbers('价格是123.45元,优惠了20%')); // [123.45, 20]
console.log(scientifictodecimal('1.23e-3')); // "0.00123"

3.4 字符串提取

从复杂文本中提取有用信息是正则表达式的强项:

/**
 * 提取url参数
 */
function extracturlparams(url) {
    const params = {};
    const match = url.match(/\?([^#]+)/);
    
    if (match) {
        const searchparams = new urlsearchparams(match[1]);
        for (const [key, value] of searchparams) {
            params[key] = value;
        }
    }
    
    return params;
}

/**
 * 提取css属性
 */
function extractcssproperties(csstext) {
    const properties = {};
    const regex = /([a-z-]+)\s*:\s*([^;]+);?/gi;
    let match;
    
    while ((match = regex.exec(csstext)) !== null) {
        properties[match[1].trim()] = match[2].trim();
    }
    
    return properties;
}

/**
 * 提取json字符串
 */
function extractjson(str) {
    const jsonregex = /\{[^{}]*\}/g;
    const matches = str.match(jsonregex);
    
    if (!matches) return [];
    
    return matches.filter(match => {
        try {
            json.parse(match);
            return true;
        } catch {
            return false;
        }
    }).map(json => json.parse(json));
}

/**
 * 提取markdown链接
 */
function extractmarkdownlinks(markdown) {
    const regex = /\[([^\]]+)\]\(([^)]+)\)/g;
    const links = [];
    let match;
    
    while ((match = regex.exec(markdown)) !== null) {
        links.push({
            text: match[1],
            url: match[2]
        });
    }
    
    return links;
}

// 测试用例
const url = 'https://example.com?name=john&age=30#section';
console.log(extracturlparams(url)); // { name: 'john', age: '30' }

const css = 'color: red; font-size: 16px; margin: 10px 20px;';
console.log(extractcssproperties(css)); // { color: 'red', 'font-size': '16px', margin: '10px 20px' }

const markdown = 'check out [google](https://google.com) and [github](https://github.com)';
console.log(extractmarkdownlinks(markdown)); // [{ text: 'google', url: 'https://google.com' }, ...]

3.5 文本替换

文本替换是正则表达式的核心功能之一:

/**
 * 智能大小写转换
 */
function smartcase(str, type = 'camel') {
    switch (type) {
        case 'camel':
            return str.replace(/(?:^\w|[a-z]|\b\w)/g, (word, index) => {
                return index === 0 ? word.tolowercase() : word.touppercase();
            }).replace(/\s+/g, '');
            
        case 'pascal':
            return str.replace(/(?:^\w|[a-z]|\b\w)/g, word => word.touppercase()).replace(/\s+/g, '');
            
        case 'kebab':
            return str.replace(/([a-z])([a-z])/g, '$1-$2').tolowercase().replace(/\s+/g, '-');
            
        case 'snake':
            return str.replace(/([a-z])([a-z])/g, '$1_$2').tolowercase().replace(/\s+/g, '_');
            
        default:
            return str;
    }
}

/**
 * 电话号码格式化
 */
function formatphonenumber(phone, format = 'national') {
    const cleaned = phone.replace(/\d/g, '');
    
    switch (format) {
        case 'national':
            return cleaned.replace(/(\d{3})(\d{4})(\d{4})/, '$1 $2 $3');
        case 'international':
            return cleaned.replace(/(\d{3})(\d{4})(\d{4})/, '+86 $1 $2 $3');
        case 'dash':
            return cleaned.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
        default:
            return cleaned;
    }
}

/**
 * 敏感词过滤
 */
function filtersensitivewords(text, sensitivewords, replacement = '***') {
    if (!array.isarray(sensitivewords) || sensitivewords.length === 0) {
        return text;
    }
    
    const pattern = sensitivewords.map(word => {
        return word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }).join('|');
    
    const regex = new regexp(pattern, 'gi');
    return text.replace(regex, replacement);
}

/**
 * 日期格式化
 */
function formatdatestring(datestr, format = 'yyyy-mm-dd') {
    const date = new date(datestr);
    if (isnan(date.gettime())) return datestr;
    
    const year = date.getfullyear();
    const month = string(date.getmonth() + 1).padstart(2, '0');
    const day = string(date.getdate()).padstart(2, '0');
    const hours = string(date.gethours()).padstart(2, '0');
    const minutes = string(date.getminutes()).padstart(2, '0');
    const seconds = string(date.getseconds()).padstart(2, '0');
    
    return format
        .replace('yyyy', year)
        .replace('mm', month)
        .replace('dd', day)
        .replace('hh', hours)
        .replace('mm', minutes)
        .replace('ss', seconds);
}

// 测试用例
console.log(smartcase('hello world', 'camel')); // "helloworld"
console.log(smartcase('hello world', 'pascal')); // "helloworld"
console.log(formatphonenumber('13800138000', 'dash')); // "138-0013-8000"
console.log(filtersensitivewords('这是一段包含敏感词的文本', ['敏感词'], '[已过滤]')); // "这是一段包含[已过滤]的文本"

4. 性能优化技巧

正则表达式的性能对大型应用至关重要:

4.1 避免回溯灾难

/**
 * 性能对比:贪婪 vs 懒惰匹配
 */
function compareperformance() {
    const teststring = 'a'.repeat(10000) + 'b';
    
    // 贪婪匹配 - 可能导致性能问题
    const greedyregex = /a.*b/;
    
    // 懒惰匹配 - 更好的性能
    const lazyregex = /a.*?b/;
    
    // 独占匹配 - 最佳性能
    const possessiveregex = /a[^b]*b/;
    
    console.time('贪婪匹配');
    greedyregex.test(teststring);
    console.timeend('贪婪匹配');
    
    console.time('懒惰匹配');
    lazyregex.test(teststring);
    console.timeend('懒惰匹配');
    
    console.time('独占匹配');
    possessiveregex.test(teststring);
    console.timeend('独占匹配');
}

4.2 预编译正则表达式

/**
 * 预编译正则表达式缓存
 */
class regexcache {
    constructor() {
        this.cache = new map();
    }
    
    get(pattern, flags = '') {
        const key = `${pattern}_${flags}`;
        
        if (!this.cache.has(key)) {
            this.cache.set(key, new regexp(pattern, flags));
        }
        
        return this.cache.get(key);
    }
    
    clear() {
        this.cache.clear();
    }
    
    size() {
        return this.cache.size;
    }
}

// 使用示例
const regexcache = new regexcache();
const emailregex = regexcache.get('^[\\w.-]+@[\\w.-]+\\.\\w+$');
console.log(emailregex.test('user@example.com')); // true

4.3 使用合适的量词

/**
 * 选择合适的量词
 */
const optimizations = {
    // 使用具体的量词而不是通用量词
    specific: {
        phone: /^\d{11}$/, // 而不是 /^\d+$/
        postalcode: /^\d{6}$/, // 而不是 /^\d+$/
    },
    
    // 使用原子组减少回溯
    atomic: {
        // 使用 (?>...) 原子组
        pattern: /(?>a+)b/,
    },
    
    // 使用 possessive 量词(在某些正则引擎中)
    possessive: {
        // javascript 不直接支持,但可以通过字符类模拟
        pattern: /a[^a]*b/,
    }
};

5. 常见错误与调试方法

5.1 常见错误

/**
 * 常见错误示例
 */
const commonmistakes = {
    // 1. 忘记转义特殊字符
    unescapeddot: /www.example.com/, // 应该为 /www\.example\.com/
    
    // 2. 使用错误的字符类
    wrongcharclass: /[a-za-z0-9_]/, // 应该使用 /\w/
    
    // 3. 贪婪匹配导致的问题
    greedyproblem: /<.*>/, // 会匹配整个字符串,应该使用 /<.*?>/
    
    // 4. 忘记全局标志
    noglobalflag: 'hello world'.replace(/o/, '0'), // 只替换第一个
    
    // 5. 错误的边界匹配
    wrongboundary: /word/, // 会匹配 "password" 中的 "word"
};

5.2 调试工具和方法

/**
 * 正则表达式调试工具
 */
class regexdebugger {
    static test(regex, testcases) {
        console.log(`测试正则表达式: ${regex}`);
        console.log('='.repeat(50));
        
        testcases.foreach(testcase => {
            const result = regex.test(testcase);
            console.log(`"${testcase}" -> ${result}`);
        });
    }
    
    static match(regex, str) {
        console.log(`在 "${str}" 中匹配 ${regex}`);
        console.log('='.repeat(50));
        
        const matches = str.match(regex);
        if (matches) {
            console.log('匹配结果:', matches);
            
            // 显示捕获组
            const execresult = regex.exec(str);
            if (execresult && execresult.length > 1) {
                console.log('捕获组:');
                for (let i = 1; i < execresult.length; i++) {
                    console.log(`  组 ${i}: ${execresult[i]}`);
                }
            }
        } else {
            console.log('无匹配结果');
        }
    }
    
    static stepbystep(regex, str) {
        console.log(`逐步匹配: ${regex} vs "${str}"`);
        console.log('='.repeat(50));
        
        let match;
        const globalregex = new regexp(regex.source, regex.flags.includes('g') ? regex.flags : regex.flags + 'g');
        
        while ((match = globalregex.exec(str)) !== null) {
            console.log(`找到匹配: "${match[0]}" 在位置 ${match.index}`);
            console.log(`剩余字符串: "${str.slice(match.index + match[0].length)}"`);
        }
    }
}

// 使用示例
const emailregex = /^[\w.-]+@[\w.-]+\.\w+$/;
const testemails = [
    'user@example.com',
    'invalid.email',
    'user.name@example.co.uk',
    '@example.com',
    'user@'
];

regexdebugger.test(emailregex, testemails);

6. 实战项目:表单验证库

让我们综合运用所学知识,创建一个完整的表单验证库:

/**
 * 表单验证库
 */
class formvalidator {
    constructor() {
        this.rules = new map();
        this.customvalidators = new map();
        this.setupdefaultrules();
    }
    
    setupdefaultrules() {
        // 内置验证规则
        this.rules.set('required', {
            pattern: /./,
            message: '此字段为必填项'
        });
        
        this.rules.set('email', {
            pattern: /^[\w.-]+@[\w.-]+\.\w+$/,
            message: '请输入有效的邮箱地址'
        });
        
        this.rules.set('phone', {
            pattern: /^1[3-9]\d{9}$/,
            message: '请输入有效的手机号码'
        });
        
        this.rules.set('idcard', {
            pattern: /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dx]$/,
            message: '请输入有效的身份证号码'
        });
        
        this.rules.set('url', {
            pattern: /^https?:\/\/(www\.)?[-a-za-z0-9@:%._\+~#=]{1,256}\.[a-za-z0-9()]{1,6}\b([-a-za-z0-9()@:%_\+.~#?&//=]*)$/,
            message: '请输入有效的url地址'
        });
        
        this.rules.set('number', {
            pattern: /^\d+(\.\d+)?$/,
            message: '请输入有效的数字'
        });
        
        this.rules.set('integer', {
            pattern: /^\d+$/,
            message: '请输入有效的整数'
        });
        
        this.rules.set('chinese', {
            pattern: /^[\u4e00-\u9fa5]+$/,
            message: '只能输入中文'
        });
        
        this.rules.set('english', {
            pattern: /^[a-za-z]+$/,
            message: '只能输入英文'
        });
        
        this.rules.set('postalcode', {
            pattern: /^\d{6}$/,
            message: '请输入有效的邮政编码'
        });
    }
    
    /**
     * 添加自定义验证规则
     */
    addrule(name, pattern, message) {
        this.rules.set(name, {
            pattern: pattern instanceof regexp ? pattern : new regexp(pattern),
            message: message
        });
        return this;
    }
    
    /**
     * 添加自定义验证器
     */
    addvalidator(name, validator) {
        if (typeof validator !== 'function') {
            throw new error('验证器必须是函数');
        }
        this.customvalidators.set(name, validator);
        return this;
    }
    
    /**
     * 验证单个值
     */
    validate(value, rules) {
        const errors = [];
        
        if (!array.isarray(rules)) {
            rules = [rules];
        }
        
        for (const rule of rules) {
            const result = this.validaterule(value, rule);
            if (result !== true) {
                errors.push(result);
            }
        }
        
        return {
            valid: errors.length === 0,
            errors: errors
        };
    }
    
    /**
     * 验证单个规则
     */
    validaterule(value, rule) {
        // 处理必填验证
        if (rule === 'required' || (typeof rule === 'object' && rule.type === 'required')) {
            if (value === null || value === undefined || value === '') {
                const message = typeof rule === 'object' && rule.message ? rule.message : this.rules.get('required').message;
                return message;
            }
            return true;
        }
        
        // 如果值为空且不是必填项,跳过验证
        if (value === null || value === undefined || value === '') {
            return true;
        }
        
        // 处理内置规则
        if (typeof rule === 'string') {
            const ruleconfig = this.rules.get(rule);
            if (!ruleconfig) {
                throw new error(`未知的验证规则: ${rule}`);
            }
            
            if (!ruleconfig.pattern.test(value)) {
                return ruleconfig.message;
            }
            return true;
        }
        
        // 处理正则表达式
        if (rule instanceof regexp) {
            if (!rule.test(value)) {
                return '格式不正确';
            }
            return true;
        }
        
        // 处理对象形式的规则
        if (typeof rule === 'object') {
            // 处理正则表达式规则
            if (rule.pattern) {
                const pattern = rule.pattern instanceof regexp ? rule.pattern : new regexp(rule.pattern);
                if (!pattern.test(value)) {
                    return rule.message || '格式不正确';
                }
                return true;
            }
            
            // 处理自定义验证器
            if (rule.validator) {
                const result = rule.validator(value);
                if (result !== true) {
                    return result || '验证失败';
                }
                return true;
            }
            
            // 处理内置规则
            if (rule.type) {
                const ruleconfig = this.rules.get(rule.type);
                if (!ruleconfig) {
                    throw new error(`未知的验证规则: ${rule.type}`);
                }
                
                if (!ruleconfig.pattern.test(value)) {
                    return rule.message || ruleconfig.message;
                }
                return true;
            }
            
            // 处理长度验证
            if (rule.minlength !== undefined || rule.maxlength !== undefined) {
                const length = value.length;
                
                if (rule.minlength !== undefined && length < rule.minlength) {
                    return rule.message || `长度不能少于${rule.minlength}个字符`;
                }
                
                if (rule.maxlength !== undefined && length > rule.maxlength) {
                    return rule.message || `长度不能超过${rule.maxlength}个字符`;
                }
                return true;
            }
            
            // 处理范围验证
            if (rule.min !== undefined || rule.max !== undefined) {
                const num = number(value);
                
                if (isnan(num)) {
                    return '请输入有效的数字';
                }
                
                if (rule.min !== undefined && num < rule.min) {
                    return rule.message || `数值不能小于${rule.min}`;
                }
                
                if (rule.max !== undefined && num > rule.max) {
                    return rule.message || `数值不能大于${rule.max}`;
                }
                return true;
            }
        }
        
        throw new error(`不支持的验证规则格式`);
    }
    
    /**
     * 验证整个表单
     */
    validateform(formdata, schema) {
        const results = {};
        let isvalid = true;
        
        for (const [field, rules] of object.entries(schema)) {
            const value = formdata[field];
            const result = this.validate(value, rules);
            
            results[field] = result;
            if (!result.valid) {
                isvalid = false;
            }
        }
        
        return {
            valid: isvalid,
            fields: results
        };
    }
}

// 使用示例
const validator = new formvalidator();

// 添加自定义规则
validator.addrule('username', /^[a-za-z][a-za-z0-9_]{5,17}$/, '用户名必须以字母开头,6-18位,只能包含字母、数字、下划线');

// 添加自定义验证器
validator.addvalidator('passwordmatch', (value, formdata) => {
    return value === formdata.password ? true : '两次输入的密码不一致';
});

// 验证单个值
console.log(validator.validate('user@example.com', 'email'));
console.log(validator.validate('13800138000', 'phone'));

// 验证整个表单
const formdata = {
    username: 'john_doe',
    email: 'john@example.com',
    phone: '13800138000',
    password: 'password123!',
    confirmpassword: 'password123!',
    age: 25
};

const schema = {
    username: ['required', 'username'],
    email: ['required', 'email'],
    phone: ['required', 'phone'],
    password: [
        'required',
        { pattern: /^(?=.*[a-z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[a-za-z\d@$!%*?&]{8,}$/, message: '密码必须包含大小写字母、数字和特殊字符,至少8位' }
    ],
    confirmpassword: [
        'required',
        { validator: (value, data) => value === data.password ? true : '两次输入的密码不一致' }
    ],
    age: [
        'required',
        { min: 18, max: 100, message: '年龄必须在18-100岁之间' }
    ]
};

console.log(validator.validateform(formdata, schema));

7. 性能测试与对比

让我们对我们的验证库进行性能测试:

/**
 * 性能测试
 */
function performancetest() {
    const validator = new formvalidator();
    const iterations = 10000;
    
    // 测试数据
    const testdata = {
        valid_email: 'user@example.com',
        invalid_email: 'invalid.email',
        valid_phone: '13800138000',
        invalid_phone: '12345678901',
        valid_url: 'https://www.example.com',
        invalid_url: 'not-a-url'
    };
    
    console.log(`开始性能测试,迭代次数: ${iterations}`);
    console.log('='.repeat(50));
    
    // 邮箱验证性能测试
    console.time('邮箱验证 (valid)');
    for (let i = 0; i < iterations; i++) {
        validator.validate(testdata.valid_email, 'email');
    }
    console.timeend('邮箱验证 (valid)');
    
    console.time('邮箱验证 (invalid)');
    for (let i = 0; i < iterations; i++) {
        validator.validate(testdata.invalid_email, 'email');
    }
    console.timeend('邮箱验证 (invalid)');
    
    // 手机号验证性能测试
    console.time('手机号验证 (valid)');
    for (let i = 0; i < iterations; i++) {
        validator.validate(testdata.valid_phone, 'phone');
    }
    console.timeend('手机号验证 (valid)');
    
    console.time('手机号验证 (invalid)');
    for (let i = 0; i < iterations; i++) {
        validator.validate(testdata.invalid_phone, 'phone');
    }
    console.timeend('手机号验证 (invalid)');
    
    // url验证性能测试
    console.time('url验证 (valid)');
    for (let i = 0; i < iterations; i++) {
        validator.validate(testdata.valid_url, 'url');
    }
    console.timeend('url验证 (valid)');
    
    console.time('url验证 (invalid)');
    for (let i = 0; i < iterations; i++) {
        validator.validate(testdata.invalid_url, 'url');
    }
    console.timeend('url验证 (invalid)');
}

// 运行性能测试
performancetest();

8. 最佳实践总结

8.1 正则表达式编写原则

  1. 简单明了:尽量使用简单的表达式,避免过度复杂
  2. 性能优先:考虑回溯和性能影响
  3. 可读性:添加注释,使用命名捕获组
  4. 测试覆盖:为每个正则表达式编写测试用例
  5. 错误处理:提供友好的错误提示

8.2 前端验证策略

  1. 客户端验证:提供即时反馈,改善用户体验
  2. 服务端验证:确保数据安全和完整性
  3. 渐进增强:从基础验证开始,逐步增加复杂度
  4. 可访问性:确保验证错误对屏幕阅读器友好

8.3 调试技巧

  1. 使用在线工具:如 regex101.com、regexr 等
  2. 逐步构建:从简单模式开始,逐步添加复杂度
  3. 单元测试:为每个正则表达式编写测试
  4. 性能分析:使用性能测试工具识别瓶颈

结语

正则表达式是前端开发中的强大工具,掌握它能够显著提升开发效率和代码质量。本文涵盖了从基础到进阶的各个方面,包括表单验证、字符串处理、性能优化等实战场景。

记住,正则表达式的学习是一个循序渐进的过程。建议从简单的模式开始,逐步增加复杂度,并在实际项目中不断练习和应用。同时,也要注意性能影响,避免过度复杂的表达式。

希望这篇文章能够帮助你在前端开发中更好地运用正则表达式,解决实际开发中遇到的各种字符串处理问题。持续学习和实践,你会发现正则表达式变得越来越简单和直观。

参考资料

到此这篇关于前端正则表达式表单验证与字符串处理高频场景的文章就介绍到这了,更多相关前端正则表达式表单验证与字符串处理内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

您想发表意见!!点此发布评论

推荐阅读

各编程语言对正则表达式标准的支持综合对比

02-28

scala正则表达式的特殊规则详解

02-28

MongoDB 正则表达式查询之如何在 MongoDB 中实现模糊搜索与索引优化陷阱

02-28

nginx负载均衡详解(轮询、权重、负载均衡)

03-02

正则表达式中的“*”为何不是通配符示例详解

03-04

从入门到精通Shell正则表达式实战

03-04

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论