🐦
Flutter: 正規表現を判定するアプリ作ってみた
以前Flutterで正規表現を使った機能を実装する機会があり、やったことのまとめも兼ねてアプリ作ってみました。
作ったもの
inputに判定対象の文字列を入力し、regexに正規表現を入力すると、resultに判定結果が出力されます。
ソースコードの解説
状態管理はChangeNotifier + Providerを使用しています。
stateを生成し
top_page_state.dart
import 'package:flutter/cupertino.dart';
class TopPageState extends ChangeNotifier {
String inputText = '';
String regexText = '';
void changeInput(String text) {
inputText = text;
notifyListeners();
}
void changeRegex(String text) {
regexText = text;
notifyListeners();
}
}
Providerで囲って使用できるようにし、Consumerを使って変更があった際にリビルドさせます。
top_page.dart
import 'package:flutter/material.dart';
import 'package:regex_test/state/top_page_state.dart';
import 'package:regex_test/widget/input_field.dart';
import 'package:regex_test/widget/output_field.dart';
import 'package:regex_test/widget/regex_text.dart';
import 'package:provider/provider.dart';
class TopPage extends StatelessWidget {
const TopPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return ChangeNotifierProvider<TopPageState>(
create: (BuildContext context) => TopPageState(),
child: GestureDetector(
onTap: () {
final FocusScopeNode currentScope = FocusScope.of(context);
if (!currentScope.hasPrimaryFocus && currentScope.hasFocus) {
FocusManager.instance.primaryFocus!.unfocus();
}
},
child: Scaffold(
appBar: AppBar(
title: const Text('Regex Checker'),
),
body: Container(
margin: const EdgeInsets.all(16),
child: SingleChildScrollView(
child: Consumer<TopPageState>(
builder: (context, state, _) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
InputField(
label: 'input',
onChanged: (String text) {
state.changeInput(text);
},
),
const SizedBox(
height: 8,
),
InputField(
label: 'regex',
onChanged: (String text) {
state.changeRegex(text);
},
),
const SizedBox(
height: 12,
),
const Align(
alignment: Alignment.centerLeft,
child: Text(
'result',
style: TextStyle(
color: Colors.grey,
),
),
),
OutputField(
child: RegexText(
text: state.inputText,
regex: state.regexText,
),
),
],
);
},
),
),
),
),
),
);
}
}
正規表現を判定し、結果を返すWidgetはこちらです。
regex_text.dart
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
class RegexText extends StatelessWidget {
const RegexText({
Key? key,
required this.text,
required this.regex,
}) : super(key: key);
final String text;
final String regex;
Widget build(BuildContext context) {
final List<TextSpan> textList = <TextSpan>[];
try {
// 正規表現で判定
final RegExp stringRegex = RegExp(
regex,
multiLine: true,
);
text.splitMapJoin(
stringRegex,
onMatch: (Match m) {
// マッチした箇所の処理
textList.add(
TextSpan(
text: m[0],
style: const TextStyle(
color: Colors.blueAccent,
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
);
return '';
},
// マッチしていない箇所の処理
onNonMatch: (String span) {
textList.add(
TextSpan(
text: span,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
);
return '';
},
);
} catch (e) {
// regexが入力途中の場合エラーが返却されることがあるので、ここでキャッチ
textList.add(
const TextSpan(
text: '正規表現が不正です',
style: TextStyle(
color: Colors.red,
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
);
}
return RichText(
text: TextSpan(
children: textList,
),
);
}
}
キーボード入力する際にテキストボックス以外をタップした場合フォーカスを外れるようにするとUX的に良いです。
GestureDetector(
onTap: () {
final FocusScopeNode currentScope = FocusScope.of(context);
if (!currentScope.hasPrimaryFocus && currentScope.hasFocus) {
FocusManager.instance.primaryFocus!.unfocus();
}
},
child: Scaffold(
・・・
),
),
参考文献
Discussion