Flutter鸿蒙开发:正则表达式工具详解

欢迎加入开源鸿蒙跨平台社区! https://openharmonycrossplatform.csdn.net

一、前言

正则表达式是文本处理的强大工具,广泛应用于数据验证、内容提取等场景。本文将详细介绍如何在Flutter鸿蒙应用中实现正则表达式工具,包括规则匹配、结果提取和替换操作等内容。

二、效果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本组件实现了以下功能:

  • 正则表达式测试
  • 常用预设模板
  • 匹配结果展示
  • 分组提取
  • 替换操作
  • 语法参考

三、技术要点

3.1 正则表达式基础

// 创建正则表达式
final regex = RegExp(r'\d+');

// 检查是否匹配
final isMatch = regex.hasMatch('abc123');

// 查找所有匹配
final matches = regex.allMatches('abc123def456');

// 替换
final replaced = 'abc123'.replaceAll(regex, 'XXX');

3.2 匹配选项

RegExp buildRegex(String pattern, {
  bool caseSensitive = true,
  bool multiline = false,
  bool dotAll = false,
}) {
  return RegExp(
    pattern,
    caseSensitive: caseSensitive,
    multiLine: multiline,
    dotAll: dotAll,
  );
}

3.3 分组提取

class MatchResult {
  final String match;
  final int start;
  final int end;
  final List<String> groups;

  MatchResult({
    required this.match,
    required this.start,
    required this.end,
    required this.groups,
  });
}

List<MatchResult> extractMatches(String input, RegExp regex) {
  return regex.allMatches(input).map((m) {
    return MatchResult(
      match: m.group(0) ?? '',
      start: m.start,
      end: m.end,
      groups: List.generate(
        m.groupCount,
        (i) => m.group(i + 1) ?? '',
      ),
    );
  }).toList();
}

四、完整实现

4.1 常用预设

class RegexPreset {
  final String id;
  final String name;
  final String pattern;

  RegexPreset(this.id, this.name, this.pattern);
}

final List<RegexPreset> presets = [
  RegexPreset('email', '邮箱', r'[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}'),
  RegexPreset('phone', '手机号', r'1[3-9]\d{9}'),
  RegexPreset('idCard', '身份证', r'\d{17}[\dXx]'),
  RegexPreset('url', 'URL', r'https?://[^\s]+'),
  RegexPreset('ip', 'IP地址', r'((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)'),
  RegexPreset('date', '日期', r'\d{4}[-/年]\d{1,2}[-/月]\d{1,2}[日]?'),
  RegexPreset('time', '时间', r'\d{1,2}:\d{2}(:\d{2})?'),
  RegexPreset('html', 'HTML标签', r'<[^>]+>'),
  RegexPreset('chinese', '中文字符', r'[\u4e00-\u9fa5]+'),
  RegexPreset('number', '数字', r'-?\d+(\.\d+)?'),
  RegexPreset('hex', '十六进制', r'#[0-9A-Fa-f]{6}|#[0-9A-Fa-f]{3}'),
  RegexPreset('whitespace', '空白字符', r'\s+'),
];

4.2 替换操作

String doReplace(String input, String pattern, String replacement) {
  try {
    final regex = RegExp(pattern);
    return input.replaceAll(regex, replacement);
  } catch (e) {
    return input;
  }
}

// 支持分组引用的替换
String replaceWithGroups(String input, String pattern, String replacement) {
  final regex = RegExp(pattern);
  return input.replaceAllMapped(regex, (match) {
    String result = replacement;
    for (int i = 0; i <= match.groupCount; i++) {
      result = result.replaceAll('\$$i', match.group(i) ?? '');
    }
    return result;
  });
}

4.3 错误处理

class RegexResult {
  final bool success;
  final List<MatchResult>? matches;
  final String? error;

  RegexResult.success(this.matches)
      : success = true,
        error = null;

  RegexResult.error(this.error)
      : success = false,
        matches = null;
}

RegexResult testRegex(String pattern, String input) {
  try {
    final regex = RegExp(pattern);
    final matches = extractMatches(input, regex);
    return RegexResult.success(matches);
  } catch (e) {
    return RegexResult.error(e.toString());
  }
}

五、界面实现

5.1 预设选择

Wrap(
  spacing: 8,
  runSpacing: 8,
  children: presets.map((preset) {
    final isSelected = selectedPreset == preset.id;
    return ActionChip(
      label: Text(preset.name),
      backgroundColor: isSelected ? Colors.indigo.shade100 : null,
      onPressed: () => loadPreset(preset),
    );
  }).toList(),
)

5.2 匹配选项

Wrap(
  spacing: 16,
  children: [
    Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Checkbox(
          value: caseSensitive,
          onChanged: (v) {
            setState(() => caseSensitive = v ?? true);
            testMatch();
          },
        ),
        const Text('区分大小写'),
      ],
    ),
    Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Checkbox(
          value: multiline,
          onChanged: (v) {
            setState(() => multiline = v ?? false);
            testMatch();
          },
        ),
        const Text('多行模式'),
      ],
    ),
    Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        Checkbox(
          value: dotAll,
          onChanged: (v) {
            setState(() => dotAll = v ?? false);
            testMatch();
          },
        ),
        const Text('.匹配换行'),
      ],
    ),
  ],
)

5.3 匹配结果展示

...List.generate(matches.length, (index) {
  final match = matches[index];
  return Container(
    margin: const EdgeInsets.only(bottom: 8),
    padding: const EdgeInsets.all(12),
    decoration: BoxDecoration(
      color: Colors.green.shade50,
      borderRadius: BorderRadius.circular(8),
    ),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          children: [
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
              decoration: BoxDecoration(
                color: Colors.green.shade200,
                borderRadius: BorderRadius.circular(12),
              ),
              child: Text('#${index + 1}'),
            ),
            const SizedBox(width: 8),
            Expanded(
              child: SelectableText(
                match.match,
                style: const TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
          ],
        ),
        Text('位置: ${match.start} - ${match.end}'),
        if (match.groups.isNotEmpty)
          Wrap(
            spacing: 8,
            children: List.generate(match.groups.length, (i) {
              return Chip(label: Text('组${i + 1}: ${match.groups[i]}'));
            }),
          ),
      ],
    ),
  );
})

六、正则表达式语法参考

6.1 基本语法

符号 说明
. 匹配任意字符(除换行)
\d 匹配数字 [0-9]
\w 匹配字母数字下划线
\s 匹配空白字符
^ 匹配行首
$ 匹配行尾

6.2 量词

符号 说明
* 0次或多次
+ 1次或多次
? 0次或1次
{n} 恰好n次
{n,m} n到m次

6.3 分组

符号 说明
(...) 捕获分组
(?:...) 非捕获分组
\1, \2 分组引用

七、最佳实践

7.1 性能优化

// 预编译常用正则表达式
final emailRegex = RegExp(r'[\w.-]+@[\w.-]+\.[a-zA-Z]{2,}');
final phoneRegex = RegExp(r'1[3-9]\d{9}');

// 避免在循环中创建正则表达式
bool validateEmail(String input) {
  return emailRegex.hasMatch(input);
}

7.2 安全处理

// 处理用户输入的正则表达式
RegExp? safeRegex(String pattern) {
  try {
    return RegExp(pattern);
  } catch (e) {
    return null;
  }
}

7.3 复杂模式建议

// 使用命名分组提高可读性
final dateRegex = RegExp(
  r'(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})'
);

// 使用详细模式(添加注释)
final regex = RegExp(r'''
  ^                   # 行首
  [\w.-]+            # 用户名部分
  @                  # @符号
  [\w.-]+            # 域名部分
  \.                 # 点号
  [a-zA-Z]{2,}       # 顶级域名
  $                   # 行尾
''', verbose: true);

八、总结

正则表达式工具是文本处理的利器。通过本文介绍的方法,开发者可以:

  1. 快速测试正则表达式
  2. 使用常用预设模板
  3. 提取匹配结果和分组
  4. 执行替换操作

在实际开发中,建议建立常用正则表达式库,提高开发效率。

九、参考资料

  • 正则表达式30分钟入门教程
  • Dart RegExp API
  • 鸿蒙文本处理指南
Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐