Flutter for OpenHarmony 文件转换助手App实战 - 正则表达式
正则表达式工具展示了如何在Flutter应用中实现文本处理功能。通过支持匹配和替换两种模式,我们为用户提供了一个完整的正则表达式解决方案。输入一变就能看到结果(pattern 侧即时反馈)错误信息可读(不要把异常堆栈直接甩给用户)预设能直接用(减少从 0 写正则的成本)结果方便复制(逐行、可选择)欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn

正则表达式是文本处理的强大工具。用户可以快速进行文本匹配和替换操作。本文将详细讲解如何实现正则表达式工具。
正则表达式工具的应用
正则表达式在文本处理中有广泛的应用。开发者可以使用正则表达式来验证邮箱、电话号码等格式。在数据提取中,正则表达式可以快速从大量文本中提取所需的信息。
在工具页面中,正则表达式工具已经定义在工具列表中:
{'icon': Icons.search, 'title': '正则表达式'},
说明
这里我把“正则表达式”作为一个独立工具入口挂在列表里,点击后进入弹窗处理。这样做的好处是:
- 页面结构更干净:主页面只负责入口展示。
- 交互更聚焦:弹窗里只做“输入-规则-输出”的闭环。
- 方便复用:后续要加“URL 编解码”“JSON 格式化”等工具时,模式一致。
正则表达式对话框的实现
当用户点击正则表达式工具时,会显示一个对话框。这个对话框提供了输入和输出的界面。
我通常会先把“打开弹窗”这一步单独封装出来,避免在列表点击事件里塞太多逻辑:
void _openRegexTool(BuildContext context) {
_showRegexDialog(context);
}
说明
这样拆开之后,列表项只负责路由/弹窗触发,真正的 UI 和业务逻辑都收敛到 _showRegexDialog 里,后面要加埋点或权限控制也更好插。
接下来是状态与输入控制器。为了让用户输入时能即时刷新结果(尤其是 pattern 改一位就能看到匹配变化),这里用 TextEditingController 会更顺手:
final _textCtrl = TextEditingController();
final _patternCtrl = TextEditingController();
final _replacementCtrl = TextEditingController();
String _resultText = '';
void dispose() {
_textCtrl.dispose();
_patternCtrl.dispose();
_replacementCtrl.dispose();
super.dispose();
}
说明
- 为什么要
dispose():弹窗/页面频繁打开关闭时,控制器不释放很容易堆积。 - 为什么要分三个控制器:匹配和替换共用“输入文本 + pattern”,替换模式再多一个 replacement,结构上最清晰。
_resultText 我会当成结果区的“缓存”,避免每次 build 都重新跑一遍匹配逻辑。用户输入很长文本时,这点差异挺明显。
弹窗骨架可以先写得很薄,只保留结构。真正的输入框/结果区域我会拆成小片段往里填:
void _showRegexDialog(BuildContext context) {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: const Text('正则表达式'),
content: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: const [],
),
),
);
},
);
},
);
}
说明
这段代码故意先留空 children,是为了避免一口气把所有输入框都塞进来导致“大片代码”。实际项目里我会把每一块都拆开写,调 UI 的时候也更专注。
下面先把“输入文本”这一块放进去:
TextField(
controller: _textCtrl,
maxLines: 6,
decoration: InputDecoration(
hintText: '输入文本',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
)
说明
maxLines稍微大一点:用户经常粘贴一段日志/JSON/代码片段做匹配,太短会来回滚。- 只做输入,不做处理:输入的处理(匹配/替换)放到 pattern 的
onChanged或执行按钮里更稳。
接着是“正则表达式”输入框。这里我更倾向做成“即时匹配”:pattern 一变就刷新结果,体验比点一次“执行”更像工具:
TextField(
controller: _patternCtrl,
maxLines: 2,
onChanged: (_) {
setState(() {});
},
decoration: InputDecoration(
hintText: '正则表达式',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
)
说明
这里的 setState 只是触发重建,实际结果怎么计算放在结果区(读取 _textCtrl.text / _patternCtrl.text)就行。弹窗里如果不用页面级 State,也可以用 StatefulBuilder 或者抽一个小组件承载状态。
最后是“结果显示区”。为了避免用户误编辑,我把它设成 readOnly:
SelectableText(
_resultText.isEmpty ? '匹配结果' : _resultText,
)
说明
结果区更像“输出面板”。如果你希望更工程化一点,也可以改成 SelectableText,便于复制,并且对长文本性能会更好。
正则表达式的匹配实现
在Dart中,我们可以使用RegExp类来进行正则表达式匹配:
String matchRegex(String text, String pattern) {
try {
final regex = RegExp(pattern);
final matches = regex.allMatches(text);
if (matches.isEmpty) {
return '没有匹配结果';
}
final results = matches.map((match) => match.group(0)).toList();
return results.join('\n');
} catch (e) {
return '正则表达式错误: $e';
}
}
说明
- 异常一定要兜住:用户输入的 pattern 很容易写错(括号不闭合、转义不正确),不 catch 会直接把弹窗搞崩。
allMatches更符合工具预期:多数场景不是“找一个”,而是把命中的片段一口气列出来。- 输出用换行拼接:简单、直观,复制到别处也方便。
如果你想让工具更像“调试器”,可以把 match.group(0) 换成输出分组信息(例如 group(1)/group(2)),但注意 UI 上要说明清楚“哪个是整体匹配、哪个是分组”。
正则表达式的替换实现
正则表达式工具还应该支持文本替换功能。用户可以指定一个正则表达式和替换文本,系统会将所有匹配的部分替换为新的文本:
String replaceRegex(String text, String pattern, String replacement) {
try {
final regex = RegExp(pattern);
return text.replaceAll(regex, replacement);
} catch (e) {
return '正则表达式错误: $e';
}
}
说明
- 替换的核心就是
replaceAll:不需要手写循环,性能和可读性都更好。 - replacement 允许
$1这类引用:Dart 的替换字符串支持捕获组引用,做“提取 + 重写”很常用。
在 UI 上我会给“替换模式”单独留一个输入框:
TextField(
controller: _replacementCtrl,
maxLines: 2,
decoration: InputDecoration(
hintText: '替换为(支持 $1 $2...)',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.r),
),
),
)
说明
这块提示语很关键,不然用户会以为 $1 是普通字符。实际项目里我还会在旁边放一个小提示,说明“$0 是整体匹配”。
常用正则表达式的预设
为了方便用户,正则表达式工具可以提供一些常用的正则表达式预设,例如邮箱验证、电话号码验证等。
我一般会用一个 Map 管理“名称 -> pattern”,后续要改规则时不至于散落在 UI 里:
const regexPresets = {
'邮箱': r'^[\w.+-]+@[\w.-]+\.[A-Za-z]{2,}$',
'手机号(简单)': r'^1\d{10}$',
'IPv4': r'^(?:\d{1,3}\.){3}\d{1,3}$',
};
说明
- 预设是“起步模板”:不追求覆盖所有边界,只要能让用户快速上手。
- 尽量用 raw string
r'':pattern 里反斜杠很多,用普通字符串会被转义搞得很难读。
当用户选择预设后,直接把 pattern 写入 _patternCtrl:
void _applyPreset(String pattern) {
_patternCtrl.text = pattern;
setState(() {});
}
说明
写入后触发一次重建,结果区就能立刻刷新。这个交互很“工具化”,用户不会觉得要额外点一次执行。
匹配结果的显示
匹配结果应该以清晰的格式显示。如果有多个匹配结果,应该逐行显示每个结果。
在弹窗的 actions 里我会保留“关闭”,并让“执行”根据当前模式去做匹配或替换:
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('关闭'),
)
说明
关闭按钮保持最简单就好,不要把清理逻辑绑在这里(否则用户只是想关掉弹窗,也会误触发清空输入)。
TextButton(
onPressed: () {
final text = _textCtrl.text;
final pattern = _patternCtrl.text;
final out = matchRegex(text, pattern);
setState(() {
_resultText = out;
});
},
child: const Text('执行'),
)
说明
- 点击执行时再读控制器:避免状态同步出错(尤其是弹窗内有多个 setState)。
- 把输出落到
_resultText:结果区不要直接在 build 里调用matchRegex做计算,输入很长时会反复重算。
如果你做了“匹配/替换”切换(比如两个 Tab 或一个 Toggle),这里的执行逻辑就可以分支:匹配走 matchRegex,替换走 replaceRegex。
总结
正则表达式工具展示了如何在Flutter应用中实现文本处理功能。通过支持匹配和替换两种模式,我们为用户提供了一个完整的正则表达式解决方案。
这类工具做到最后,体验差异往往不在“能不能跑”,而在这些细节上:
- 输入一变就能看到结果(pattern 侧即时反馈)
- 错误信息可读(不要把异常堆栈直接甩给用户)
- 预设能直接用(减少从 0 写正则的成本)
- 结果方便复制(逐行、可选择)
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)