今天一位同事跟我说遇到个奇怪的问题。自己写了个简单的手机号校验正则表达式,然后明明输入的标准手机号却一直走的校验不通过分支。我同事已经开始怀疑自己的手机号是假的了😂,大伙先看下代码示例:
const RegExDemo = () => {
const [tel, setTel] = useState(() => '');
const $msg = useRef(null);
// 使用useMemo()缓存正则表达式,避免每次都要计算
const validateTel = useMemo(() => {
// 设置除了"1"以外的第一个字符必须是3-9之间的 其余10位是任意数字
return /^1[3-9]\d{9}$/g;
}, []);
// 使用useEffect()处理DOM更新
useEffect(() => {
if (!$msg.current) return;
console.log('validateTel.test(tel):', validateTel.test(tel));
if(validateTel.test(tel)) {
$msg.current.style.display = 'none';
} else {
$msg.current.style.display = 'block';
}
}, [tel, validateTel]);
/**
* 输入框值变化
* @param {} event
*/
const _onInputChange = (event) => {
// 更新组件状态,将tel存储在useState回调中
setTel(() => {
return event.target.value;
});
}
return (
<div className='form'>
<span>手机号</span>
<Input type='text' className='tel-input' value={tel} onChange={_onInputChange}/>
<span ref={$msg} className='msg'>手机号格式不正确</span>
</div>
);
};
看上去好像没什么问题吧,然后在输入框里输入标准手机号,看下结果:
多么标准的手机号,而且明明打印的校验结果是true,竟然提示格式不正确?离了个大谱!要知道这个问题原因,就要看正则的掌握情况如何。
问题原因
所有的正则表达式都有一个lastIndex属性,用于标识下一次匹配开始查找的位置。如果未使用全局匹配,lastIndex的值始终为0,而如果通过使用‘g’标识符或者设置global属性值为true时,那么正则表达式将对要匹配的字符串进行全局匹配,会执行多次匹配。在使用全局匹配的情况下,找到匹配的项后lastIndex的值被设置为匹配内容的下一个字符在字符串中的位置索引,找不到匹配项则设置为0;
在上面的例子中加了全局标识‘g’,然后在判断语句前的打印语句中调用了test方法,在匹配成功后lastIndex的值已经设置成了11,所以在if语句中的那次test就是从索引为11的位置去匹配,结果就成了false。将lastIndex的值打印出来看下,如图:
解决办法
1.删除日志打印行(这种方式发生bug的概率还是比较高),如下:
2.去掉全局标识‘g’
3.如果非得使用全局的情况,那么可以将lastIndex重置为0
本文来自博客园,作者:你比从前快乐KX,转载请注明原文链接:https://www.cnblogs.com/sweetdreamkx/p/17393627.html