Skip to content

pattern 正则验证

pattern 属性使用正则表达式对输入值进行格式验证。它为文本类型的输入控件提供了强大的格式约束能力,如手机号、身份证号、邮编等。pattern 必须与 title 属性配合使用,为用户提供验证失败时的说明。

前置知识

阅读本节前,建议先了解:required 必填验证

基础概念

什么是 pattern 验证

pattern 属性接受一个 JavaScript 正则表达式,当用户提交表单时,浏览器会检查输入值是否匹配该模式。如果不匹配,验证失败并显示 title 属性中的提示信息。

  • 正则表达式:使用 JavaScript 兼容的正则语法
  • 全量匹配:默认在正则两端隐式添加 ^(?:...)$
  • 配合 titletitle 属性提供验证失败时的提示文本
  • 空值不验证:如果控件值为空,pattern 不会触发验证(需要 required

注意:隐式全量匹配

pattern 的正则表达式会自动匹配整个输入值,相当于隐式包裹 ^(?:...)$。因此不需要手动添加 ^$ 锚点:

html
<!-- 不需要 ^ 和 $,浏览器自动包裹 -->
<input pattern="[0-9]{3}-[0-9]{4}">
<!-- 实际匹配:^(?:[0-9]{3}-[0-9]{4})$ -->

语法

基本用法

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>pattern 基本示例</title>
</head>
<body>
    <h2>手机号验证</h2>
    <form>
        <label for="phone">手机号码:</label>
        <input
            type="tel"
            id="phone"
            name="phone"
            pattern="1[3-9]\d{9}"
            title="请输入 11 位手机号,以 1 开头,第二位为 3-9"
            required
            placeholder="13800138000"
        >
        <button type="submit">提交</button>
    </form>
</body>
</html>

pattern 与 title 配合

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>pattern + title</title>
</head>
<body>
    <h2>邮编验证</h2>
    <form>
        <label for="zipcode">邮政编码:</label>
        <input
            type="text"
            id="zipcode"
            name="zipcode"
            pattern="\d{6}"
            title="请输入 6 位数字邮政编码"
            required
            placeholder="100000"
        >
        <button type="submit">提交</button>
    </form>
    <p>验证失败时,浏览器会显示 title 中的提示文字。</p>
</body>
</html>

详细说明

常用 pattern 示例

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>常用 pattern</title>
    <style>
        body { font-family: sans-serif; max-width: 700px; margin: 40px auto; }
        .form-group { margin-bottom: 12px; }
        label { display: block; margin-bottom: 4px; font-weight: 600; }
        input {
            padding: 8px 12px;
            border: 2px solid #ddd;
            border-radius: 6px;
            width: 300px;
        }
        table { border-collapse: collapse; width: 100%; margin-top: 16px; }
        th, td { padding: 8px; text-align: left; border: 1px solid #ddd; }
        code { background: #f5f5f5; padding: 2px 6px; border-radius: 3px; font-size: 13px; }
    </style>
</head>
<body>
    <h2>常用 pattern 模式</h2>
    <form>
        <div class="form-group">
            <label for="cn-phone">中国手机号:</label>
            <input type="tel" id="cn-phone" pattern="1[3-9]\d{9}"
                   title="11位手机号,1开头,第二位3-9" placeholder="13800138000">
        </div>
        <div class="form-group">
            <label for="cn-zip">中国邮编:</label>
            <input type="text" id="cn-zip" pattern="\d{6}"
                   title="6位数字邮政编码" placeholder="100000">
        </div>
        <div class="form-group">
            <label for="cn-id">身份证号(18位):</label>
            <input type="text" id="cn-id" pattern="\d{17}[\dXx]"
                   title="18位身份证号" placeholder="110101199001011234">
        </div>
        <div class="form-group">
            <label for="username">用户名(字母数字下划线):</label>
            <input type="text" id="username" pattern="[a-zA-Z0-9_]{3,20}"
                   title="3-20位字母、数字或下划线" placeholder="user_01">
        </div>
        <div class="form-group">
            <label for="hex-color">十六进制颜色:</label>
            <input type="text" id="hex-color" pattern="#[0-9a-fA-F]{6}"
                   title="6位十六进制颜色值" placeholder="#4a90d9">
        </div>
        <div class="form-group">
            <label for="ip">IPv4 地址:</label>
            <input type="text" id="ip"
                   pattern="((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)"
                   title="IPv4 格式" placeholder="192.168.1.1">
        </div>
        <div class="form-group">
            <label for="no-space">不允许空格:</label>
            <input type="text" id="no-space" pattern="\S+"
                   title="不能包含空格" placeholder="无空格文本">
        </div>
    </form>

    <h3>常用 pattern 速查表</h3>
    <table>
        <tr><th>场景</th><th>pattern</th><th>说明</th></tr>
        <tr><td>中国手机号</td><td><code>1[3-9]\d{9}</code></td><td>11位,1开头</td></tr>
        <tr><td>邮编</td><td><code>\d{6}</code></td><td>6位数字</td></tr>
        <tr><td>身份证</td><td><code>\d{17}[\dXx]</code></td><td>18位</td></tr>
        <tr><td>用户名</td><td><code>[a-zA-Z0-9_]{3,20}</code></td><td>字母数字下划线</td></tr>
        <tr><td>大写字母</td><td><code>[A-Z]+</code></td><td>纯大写</td></tr>
        <tr><td>十六进制颜色</td><td><code>#[0-9a-fA-F]{6}</code></td><td>#rrggbb</td></tr>
        <tr><td>无空格</td><td><code>\S+</code></td><td>非空白字符</td></tr>
    </table>
</body>
</html>

空值不触发 pattern 验证

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>pattern 空值行为</title>
</head>
<body>
    <h2>pattern 与空值</h2>
    <form>
        <p>以下手机号字段有 pattern 但没有 required:</p>
        <label for="phone">手机号(选填):</label>
        <input type="tel" id="phone" name="phone"
               pattern="1[3-9]\d{9}" title="请输入有效手机号">
        <button type="submit">提交</button>
    </form>

    <p>用户可以留空提交(pattern 不会验证空值)。</p>
    <p>如果要求必须填写且格式正确,需要同时添加 <code>required</code>:</p>

    <form>
        <label for="phone2">手机号(必填):</label>
        <input type="tel" id="phone2" name="phone2"
               pattern="1[3-9]\d{9}" title="请输入有效手机号" required>
        <button type="submit">提交</button>
    </form>
</body>
</html>

JavaScript 动态设置 pattern

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>动态 pattern</title>
</head>
<body>
    <h2>动态验证规则</h2>
    <form id="dynamic-form">
        <div>
            <label for="input-type">验证类型:</label>
            <select id="input-type">
                <option value="phone">手机号</option>
                <option value="email">邮箱</option>
                <option value="zip">邮编</option>
                <option value="none">无验证</option>
            </select>
        </div>
        <div>
            <label for="input-value">输入值:</label>
            <input type="text" id="input-value" name="value" placeholder="根据上方类型输入">
        </div>
        <button type="submit">验证</button>
    </form>
    <p id="result"></p>

    <script>
        const patterns = {
            phone: { pattern: '1[3-9]\\d{9}', title: '请输入11位手机号' },
            email: { pattern: '[^@]+@[^@]+\\.[^@]+', title: '请输入有效邮箱' },
            zip:   { pattern: '\\d{6}', title: '请输入6位邮编' },
            none:  { pattern: '', title: '' }
        };

        const typeSelect = document.getElementById('input-type');
        const input = document.getElementById('input-value');

        typeSelect.addEventListener('change', function () {
            const rule = patterns[this.value];
            if (rule.pattern) {
                input.pattern = rule.pattern;
                input.title = rule.title;
                input.placeholder = `格式:${rule.title}`;
            } else {
                input.removeAttribute('pattern');
                input.removeAttribute('title');
                input.placeholder = '无需特定格式';
            }
        });
    </script>
</body>
</html>

实战示例

多字段格式验证

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>多字段 pattern 验证</title>
    <style>
        body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }
        .form-group { margin-bottom: 16px; }
        label { display: block; margin-bottom: 4px; font-weight: 600; }
        input {
            width: 100%;
            padding: 8px 12px;
            border: 2px solid #ddd;
            border-radius: 6px;
            box-sizing: border-box;
        }
        input:valid { border-color: #27ae60; }
        input:invalid:not(:focus):not(:placeholder-shown) { border-color: #e74c3c; }
        .hint { font-size: 13px; color: #666; margin-top: 2px; }
        button {
            padding: 10px 24px;
            background: #4a90d9;
            color: #fff;
            border: none;
            border-radius: 6px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <h2>信息验证</h2>
    <form id="verify-form">
        <div class="form-group">
            <label for="name">用户名:</label>
            <input type="text" id="name" name="name"
                   pattern="[a-zA-Z0-9\u4e00-\u9fa5_]{2,16}"
                   title="2-16位中英文、数字或下划线"
                   required placeholder="用户名">
            <p class="hint">2-16位中英文、数字或下划线</p>
        </div>
        <div class="form-group">
            <label for="phone">手机号:</label>
            <input type="tel" id="phone" name="phone"
                   pattern="1[3-9]\d{9}"
                   title="请输入11位手机号"
                   required placeholder="13800138000">
            <p class="hint">11位手机号</p>
        </div>
        <div class="form-group">
            <label for="invite-code">邀请码:</label>
            <input type="text" id="invite-code" name="invite_code"
                   pattern="[A-Z]{2}-\d{4}"
                   title="格式:XX-0000(2大写字母-4数字)"
                   placeholder="AB-1234">
            <p class="hint">格式:XX-0000</p>
        </div>
        <button type="submit">提交验证</button>
    </form>

    <script>
        document.getElementById('verify-form').addEventListener('submit', function (e) {
            e.preventDefault();
            if (this.checkValidity()) {
                alert('验证通过!');
            } else {
                this.reportValidity();
            }
        });
    </script>
</body>
</html>

注意事项

pattern 不适用于所有类型

pattern 仅适用于基于文本的输入类型(textsearchtelurlemailpassword)。对 numberdaterange 等类型无效。

正则中的反斜杠需要双重转义

在 HTML 属性中,反斜杠需要双重转义:

html
<!-- HTML 属性中的正则 -->
<input pattern="\\d{6}">

<!-- JavaScript 中的正则 -->
<input pattern="\d{6}">

空值通过 pattern 验证

如果用户未输入任何值(空字符串),pattern 不会触发验证。需要搭配 required 强制填写。

最佳实践

  1. 始终配合 title:为 pattern 提供清晰的错误说明
  2. 提供格式提示:在 placeholder 或说明文字中展示正确格式
  3. 正则简洁实用:不要过度复杂的正则,兼顾可读性和实用性
  4. 结合 required:需要必填的字段同时添加 required
  5. 服务端二次验证:客户端验证可绕过,服务端必须再次校验
  6. 测试正则:在浏览器中充分测试正则的正确性

下一节

继续学习:min / max / step

参考链接