Flutter中使用正则表达式验证喀麦隆手机号及识别运营商
喀麦隆手机号验证与运营商识别(Flutter实现)
原正则问题分析
你写的正则(^6+(?:\+?8|7|5[1-4])+[0-9]{9}$)存在几个关键问题:
6+会匹配多个连续的6,不符合“以单个6开头”的规则- 分组后的
+会重复匹配运营商前缀,导致格式混乱;且\+?完全多余,因为通用规则已经排除了特殊字符 - 长度计算错误:喀麦隆手机号总长9位,原正则里
[0-9]{9}会让总长度远超要求
修正后的正则表达式
先定义通用验证规则,再分别匹配MTN和Orange:
通用验证(确保符合喀麦隆手机号基础格式)
// 9位数字,以6开头,无其他字符 RegExp generalCameroonPhone = RegExp(r'^6\d{8}$');
MTN CM 匹配规则
// 第二位为7/8,或第二位为5且第三位是0-4,后续6位任意数字 RegExp mtnCMRegex = RegExp(r'^6(7|8|5[0-4])\d{6}$');
Orange CM 匹配规则
// 第二位为9,或第二位为5且第三位是5-9,后续6位任意数字 RegExp orangeCMRegex = RegExp(r'^6(9|5[5-9])\d{6}$');
完整实现步骤
1. 状态管理与运营商识别
用枚举标记当前识别的运营商,监听输入变化实时判断:
enum CameroonCarrier { none, mtn, orange } class PhoneVerificationPage extends StatefulWidget { const PhoneVerificationPage({super.key}); @override State<PhoneVerificationPage> createState() => _PhoneVerificationPageState(); } class _PhoneVerificationPageState extends State<PhoneVerificationPage> { final TextEditingController _phoneController = TextEditingController(); final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); CameroonCarrier _currentCarrier = CameroonCarrier.none; // 实时检查运营商 void _checkCarrier(String input) { setState(() { if (!generalCameroonPhone.hasMatch(input)) { _currentCarrier = CameroonCarrier.none; return; } if (mtnCMRegex.hasMatch(input)) { _currentCarrier = CameroonCarrier.mtn; } else if (orangeCMRegex.hasMatch(input)) { _currentCarrier = CameroonCarrier.orange; } else { _currentCarrier = CameroonCarrier.none; } }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('手机号验证')), body: Padding( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( children: [ TextFormField( controller: _phoneController, keyboardType: TextInputType.phone, onChanged: _checkCarrier, decoration: InputDecoration( labelText: '喀麦隆手机号', hintText: '例如:688684749', // 根据运营商显示Logo suffixIcon: _currentCarrier == CameroonCarrier.mtn ? Image.asset('assets/mtn_logo.png', width: 32, height: 32) : _currentCarrier == CameroonCarrier.orange ? Image.asset('assets/orange_logo.png', width: 32, height: 32) : null, ), validator: (value) { if (value == null || value.isEmpty) { return '请输入手机号'; } if (!generalCameroonPhone.hasMatch(value)) { return '请输入有效的9位喀麦隆手机号(以6开头)'; } if (_currentCarrier == CameroonCarrier.none) { return '无法识别运营商,请检查号码'; } return null; }, ), const SizedBox(height: 20), ElevatedButton( onPressed: () { // 验证通过才执行提交 if (_formKey.currentState?.validate() == true) { // 这里写你的提交逻辑 ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('提交号码:${_phoneController.text}')), ); } }, child: const Text('提交'), ), ], ), ), ), ); } }
2. 注意事项
- 替换代码中的
assets/mtn_logo.png和assets/orange_logo.png为你实际的Logo资源路径,并在pubspec.yaml中配置资源 - 若需要处理带国家码
+237的情况,可以在验证前先移除国家码,再用上述正则判断:String cleanedPhone = value.replaceAll(RegExp(r'^\+237'), '');
内容的提问来源于stack exchange,提问作者ASA Serge
相关产品推荐
相关产品推荐

