地址表单前端校验:正则表达式与最佳实践
地址表单前端校验详解
地址表单是开发中最常见的表单类型之一,但又是字段规则最复杂的。
地址字段构成
典型的美国地址表单包含以下字段:
| 字段 | 必填 | 长度限制 | 校验规则 |
|---|---|---|---|
| 姓名 (Name) | 是 | 1-100 | 字母、空格、连字符 |
| 街道 (Street) | 是 | 1-200 | 字母、数字、空格、特殊符号 |
| 公寓号 (Apt/Suite) | 否 | 1-20 | 字母数字组合 |
| 城市 (City) | 是 | 1-100 | 字母、空格、连字符 |
| 州 (State) | 是 | 2 | 50州代码之一 |
| 邮编 (ZIP) | 是 | 5 或 10 | 数字 + 可选连字符 |
| 国家 (Country) | 是 | 2 | ISO 国家代码 |
| 电话 (Phone) | 是 | 10 | 数字 (美国格式) |
常用正则表达式
街道地址
```javascript
// 基础街道地址
const streetRegex = /^[a-zA-Z0-9\s.,#\-]+$/;
// 允许公寓号
const streetWithAptRegex = /^[a-zA-Z0-9\s.,#\-]+(apt|suite|ste|unit|#)?\.?\s*[a-zA-Z0-9\-]*$/i;
```
城市名
```javascript
// 字母、空格、连字符、撇号
const cityRegex = /^[a-zA-Z\s.'\-]{1,100}$/;
```
州代码
```javascript
const stateRegex = /^(A[KLRZ]|C[AOT]|D[CE]|FL|GA|HI|I[ADLN]|K[SY]|LA|M[ADEINOST]|N[CDEHJMVY]|O[HKR]|PA|RI|S[CD]|T[NX]|UT|V[AT]|W[AIVY])$/;
```
邮编
```javascript
// 仅5位
const zip5Regex = /^\d{5}$/;
// ZIP+4
const zip9Regex = /^\d{5}-\d{4}$/;
// 兼容两种
const zipRegex = /^\d{5}(-\d{4})?$/;
```
电话
```javascript
// 美国格式
const phoneRegex = /^\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/;
// 严格E.164格式
const phoneE164Regex = /^\+1\d{10}$/;
```
完整校验函数
```javascript
function validateAddress(address) {
const errors = {};
// 姓名
if (!address.name || address.name.trim().length === 0) {
errors.name = '请输入姓名';
} else if (address.name.length > 100) {
errors.name = '姓名不能超过100字符';
}
// 街道
if (!address.street || !streetRegex.test(address.street)) {
errors.street = '街道格式不正确';
}
// 城市
if (!address.city || !cityRegex.test(address.city)) {
errors.city = '城市名格式不正确';
}
// 州
if (!address.state || !stateRegex.test(address.state.toUpperCase())) {
errors.state = '请选择有效的州';
}
// 邮编
if (!address.zip || !zipRegex.test(address.zip)) {
errors.zip = '邮编格式不正确';
}
return Object.keys(errors).length === 0 ? null : errors;
}
```
实时校验实现
```javascript
import { useState } from 'react';
function AddressForm() {
const [formData, setFormData] = useState({
name: '', street: '', city: '', state: '', zip: ''
});
const [errors, setErrors] = useState({});
const handleChange = (field) => (e) => {
const value = e.target.value;
setFormData(prev => ({ ...prev, [field]: value }));
// 失焦后再校验
if (errors[field]) {
const newErrors = { ...errors };
delete newErrors[field];
setErrors(newErrors);
}
};
const handleBlur = (field) => () => {
if (formData[field]) {
const fieldError = validateField(field, formData[field]);
setErrors(prev => ({ ...prev, [field]: fieldError }));
}
};
return (
<form>
<input
value={formData.name}
onChange={handleChange('name')}
onBlur={handleBlur('name')}
placeholder="姓名"
/>
{errors.name && <span className="error">{errors.name}</span>}
{/* 其他字段... */}
</form>
);
}
```
常见错误处理
1. 用户输入特殊字符
某些街道名包含特殊字符:
| 街道名 | 处理方式 |
|---|---|
| O'Reilly Street | 允许撇号 |
| Smith & Jones Ave | 允许 `&` |
| 123 1/2 Main St | 允许斜杠 |
| 456 Highway 50 | 允许 Highway |
2. 国际地址
如果表单支持国际地址:
3. 字符大小写
| 字段 | 存储格式 |
|---|---|
| 姓名 | Title Case: `John Smith` |
| 街道 | Title Case: `123 Main Street` |
| 城市 | Title Case: `San Francisco` |
| 州 | Upper Case: `CA` |
| 邮编 | 原样保存 |
UX 优化建议
- 邮编:`inputmode="numeric"`
- 电话:`inputmode="tel"`
测试数据生成
使用我们的美国地址生成器可以快速生成测试数据,覆盖:
总结
地址表单的校验需要兼顾:
掌握这些规则能帮助你构建既严格又易用的地址表单。