正規表現で文字列の否定⑤
文字列処理でやってみた
とりあえず ここ で以下の16個の正規表現を生成して、それらのルールを分析して、C#のメソッド作ってみたよ。
- Regex01:文字列"0"を含まない任意の文字列とマッチする正規表現
- Regex02:文字列"01"を含まない任意の文字列とマッチする正規表現
- Regex03:文字列"012"を含まない任意の文字列とマッチする正規表現
- ...
- Regex16:文字列"0123456789ABCDEF"を含まない任意の文字列とマッチする正規表現
ちなみに、生成して分析していた正規表現は以下。
ルールが見えやすいように、正規表現の縦を合わせてるけど、実際はスペースは無いよ。
Regex01: ^[^0]*$ Regex02: ^([^0]|0+ [^01])* 0*$ Regex03: ^([^0]|0(0|10)* ([^01]|1[^02]))* (0(0|10)* 1?)?$ Regex04: ^([^0]|0(0|1(0|20))* ([^01]|1([^02]|2[^03])))* (0(0|1(0|20))* (12?)?)?$ Regex05: ^([^0]|0(0|1(0|2(0|30)))* ([^01]|1([^02]|2([^03]|3[^04]))))* (0(0|1(0|2(0|30)))* (1(2?|23))?)?$ Regex06: ^([^0]|0(0|1(0|2(0|3(0|40))))* ([^01]|1([^02]|2([^03]|3([^04]|4[^05])))))* (0(0|1(0|2(0|3(0|40))))* (1(2?|234?))?)?$ Regex07: ^([^0]|0(0|1(0|2(0|3(0|4(0|50)))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5[^06]))))))* (0(0|1(0|2(0|3(0|4(0|50)))))* (1(2?|23(4?|45)))?)?$ Regex08: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|60))))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6[^07])))))))* (0(0|1(0|2(0|3(0|4(0|5(0|60))))))* (1(2?|23(4?|456?)))?)?$ Regex09: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|6(0|70)))))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6([^07]|7[^08]))))))))* (0(0|1(0|2(0|3(0|4(0|5(0|6(0|70)))))))* (1(2?|23(4?|45(6?|67))))?)?$ Regex10: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|80))))))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6([^07]|7([^08]|8[^09])))))))))* (0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|80))))))))* (1(2?|23(4?|45(6?|678?))))?)?$ Regex11: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|90)))))))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6([^07]|7([^08]|8([^09]|9[^0A]))))))))))* (0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|90)))))))))* (1(2?|23(4?|45(6?|67(8?|89)))))?)?$ Regex12: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A0))))))))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6([^07]|7([^08]|8([^09]|9([^0A]|A[^0B])))))))))))* (0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A0))))))))))* (1(2?|23(4?|45(6?|67(8?|89A?)))))?)?$ Regex13: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A(0|B0)))))))))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6([^07]|7([^08]|8([^09]|9([^0A]|A([^0B]|B[^0C]))))))))))))* (0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A(0|B0)))))))))))* (1(2?|23(4?|45(6?|67(8?|89(A?|AB))))))?)?$ Regex14: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A(0|B(0|C0))))))))))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6([^07]|7([^08]|8([^09]|9([^0A]|A([^0B]|B([^0C]|C[^0D])))))))))))))* (0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A(0|B(0|C0))))))))))))* (1(2?|23(4?|45(6?|67(8?|89(A?|ABC?))))))?)?$ Regex15: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A(0|B(0|C(0|D0)))))))))))))* ([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6([^07]|7([^08]|8([^09]|9([^0A]|A([^0B]|B([^0C]|C([^0D]|D[^0E]))))))))))))))* (0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A(0|B(0|C(0|D0)))))))))))))* (1(2?|23(4?|45(6?|67(8?|89(A?|AB(C?|CD)))))))?)?$ Regex16: ^([^0]|0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A(0|B(0|C(0|D(0|E0))))))))))))))*([^01]|1([^02]|2([^03]|3([^04]|4([^05]|5([^06]|6([^07]|7([^08]|8([^09]|9([^0A]|A([^0B]|B([^0C]|C([^0D]|D([^0E]|E[^0F])))))))))))))))*(0(0|1(0|2(0|3(0|4(0|5(0|6(0|7(0|8(0|9(0|A(0|B(0|C(0|D(0|E0))))))))))))))*(1(2?|23(4?|45(6?|67(8?|89(A?|AB(C?|CDE?)))))))?)?$
LibreOfficeで二重丸描きたい
オートマトンの受理状態を描くときに、今までオレンジ色で塗りつぶした円を描いてた。
だけど、できれば二重丸でかきたいなーとずっと思ってて、良いやり方見つけた。
基本シェイプの中にある「円」じゃなくて「輪」を使えば良さげ。

内側の円も拡大縮小できるので二重線に見えるように拡大してやると良さげ。内側の円はあくまで穴の想定なので、塗りつぶし出来ないっぽい。だけどそれはまた別のアプリ使って何とかしよう。
線のプロパティに「実線」とか「点線」とかあるけど、「二重線」を追加してくれれば、任意のシェイプで二重線使えるのにな。
こうなりました

正規表現で文字列の否定②
まずは文字列abを含まない文字列から考えてみた。僕ははあまり賢くないので、いきなり正規表現で考えると分からなくなりそうだったので、状態遷移図を描きつつ、有限オートマトンM0を構成してみた。オレンジ色の状態が受理状態で、いったん状態3に到達したら必ず不受理になる。

どうやら状態0と状態2は等価なようだ。これらをまとめて、整理して、M1としてみた。

この決定性有限オートマトンM1を、それと等価な正規表現に変換したいなぁ。
どうすりゃ良いのかな?
なんか良い感じの説明みつけた(2022/04/30 21:18 追記)
www.momoyama-usagi.com
「3.正規表現と有限オートマトン」の「(1) ただの文字列」から「(4) いずれかを表す |」を参考に考えてみよう。
正規表現で文字列の否定①
bynatures.hatenadiary.jp
を読んで、「正規表現は否定を上手く表せない?マジか!!」って思ったので、やってみた。とりあえず、紹介されている例を確かめてみた。
https://ideone.com/a38njo
ん...??なんか変じゃね??