トップ回答者
パターンマッチング 正規表現:半角大文字アルファベットと、半角数字、それぞれ一文字以上含めば True

質問
-
いつも大変にお世話になっております。
半角のアルファベット[A-Z]と、半角の数字[0-9]ともに、それぞれ1文字以上を含む判定をしたいのですが、パターンマッチングが分からず行き詰っております。どうかご教示いただけませんでしょうか。
出したい答え
A1 → True、AA11 → True、AAA → False、111 → False、a1 → False、@1 → False次のような関数を組んでみました。
Private Function NewPasswordCheck(ByVal NewPass1 As String) As Boolean
If Not System.Text.RegularExpressions.Regex.IsMatch(NewPass1, "^[0-9]+$") AndAlso
Not System.Text.RegularExpressions.Regex.IsMatch(NewPass1, "^[A-Z]+$") ThenMessageBox.Show("パスワードには[数字]と[英字]がそれぞれ" & vbCrLf &
"1文字ずつ以上含まれていなければなりません。", "入力値エラー",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
Return FalseEnd If
Return True
End Function
ですがこれですと、A1 → True で、希望どおりなのですが、これだけに留まらず、
A だけの場合でも True になり、1 だけの場合でも True になってしまいます。これをなんとか、AND または AndAldo を使って、一発で条件に合う
パターンマッチングにする方法はございませんでしょうか?それとこのパターンマッチングを改良して、上記条件 + 文字の桁が 4桁以上、8桁以下
となるような、判定パターンを書くことができるようでしたら、合わせてご教示いただくことは
できませんでしょうか。どうか、よろしくお願い申し上げます。
- 編集済み kei_chan_gt 2013年8月1日 9:07 再度、書式体裁を整えました。
回答
-
このあたり ↓ を読むときっと答えが見つかると思います。
ASP.NET の正規表現
http://msdn.microsoft.com/ja-jp/library/ms972966.aspx正規表現での量指定子
http://msdn.microsoft.com/ja-jp/library/vstudio/3206d374.aspx- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
こんな?
Sub Main() Dim reg As New System.Text.RegularExpressions.Regex("^(?!(?!.{4,8}$))[0-9A-Z]*([0-9][A-Z]|[A-Z][0-9])+[0-9A-Z]*$") Dim ss As String() = {"A1", "1A", "AA1", "AAA", "111", "a1", "@1", "1A", "A1A", "1A1", "1a1", "@1"} For length As Integer = 3 To 9 For Each s As String In ss Dim s2 As String s2 = s.PadRight(length, "1"c) Console.WriteLine(s2 + vbTab + reg.IsMatch(s2).ToString()) s2 = s.PadRight(length, "A"c) Console.WriteLine(s2 + vbTab + reg.IsMatch(s2).ToString()) Next Next End Sub
2013/08/02 20:40 二重否定を使った理由の追記
回答が酷過ぎるとレスをもらいました。「サンプルコード付きで回答した」のが酷いのか、「正しくないコード」(動作検証してあります)だから酷いのか、「コードが汚い」から酷いのか、「二重否定を使った」のが酷いのか、…(以下略)、理由が読み取れなかったので、二重否定を使った理由だけは説明。正規表現の先読みには「正の先読み(?=○)」と「負の先読み(?!○)」があります。
ですが、使おうとする時に書き方を忘れることがよくあります。
そんな時は「負の先読み」だけ覚えておけば二重否定を使うことでどちらの機能も実現できます。
覚えておくことが半分になるなんてお得だよね?
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 編集済み gekkaMVP 2013年8月2日 11:49
- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
これをなんとか、AND または AndAldo を使って、一発で条件に合うパターンマッチングにする方法はございませんでしょうか?
たぶん正規表現そのもの問題ではないと思います。中学か高校の数学で習うはずのド・モルガンの法則とかその辺り、NotやAndAlsoを重ねたときに何がTrueになるのか、逆に欲しい条件にするにはどう組み合わせればいいのか、その辺りができていないだけだと思います。
その上で、パターンマッチングの質問として答えるならば、上記のややこしさ、考慮漏れなどもあるため、Regex.IsMatch()を1回で完了できるようパターンを記述することをお勧めします。
つまり、「半角大文字アルファベットと、半角数字、それぞれ一文字以上含めば True」を更に噛み砕いて理解することが重要です。
これを「全角大文字アルファベット1文字以上の後に半角数字1文字以上、または半角数字1文字以上の後に全角大文字アルファベット1文字以上」に読み替えることができれば表現できるはずです。ところで小文字や記号、全角文字が含まれていた場合はどうなってほしいのでしょうか。
- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
Private Function NewPasswordCheck(ByVal NewPass1 As String) As Boolean If NewPass1.Length < 4 OrElse NewPass1.Length > 8 Then MessageBox.Show("パスワードは4桁以上8桁以下で入力して下さい。" _ , "入力値エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Return False End If If System.Text.RegularExpressions.Regex.IsMatch(NewPass1, "^[0-9]+$") AndAlso _ System.Text.RegularExpressions.Regex.IsMatch(NewPass1, "^[A-Z]+$") Then Return True Else MessageBox.Show("パスワードには[数字]と[英字]がそれぞれ" & vbCrLf & "1文字ずつ以上含まれていなければなりません。" _ , "入力値エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Return False End If End Function
元々の造りを踏襲して、こんな感じでも良い気がします。- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
いくらなんでもその正規表現は…二重否定入ってますし。好き放題書いていいのなら
"^(?:(?<upper>[A-Z])|(?<number>[0-9])|.){4,8}$(?(upper)|(?!))(?(number)|(?!))"
とか書けますけど、回答として提示するには酷過ぎると思います。
ところでサンプルに a1 や @1 があるということは、 aA1 や @A1 はTrueになるべきなのかな?
- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
コードを書いている回答者の方がおられますが、自分の意図する方向とちょっと違うようなので、自分のお勧めを具体的に書いておきます。
先のレスで紹介した「ASP.NET の正規表現」のページの「高度なトピック」のセクションに書いてある "ルックアラウンド処理" を利用するのが便利だと思います。
今回の問題では以下のような感じになると思います。
Regex regex = new Regex(@" ^ # 開始のアンカー (?=.*\d) # 数字が 1 文字必要 (?=.*[A-Z]) # 大文字が 1 文字必要 [A-Z0-9]{2,} # 大文字、数字 2 文字以上の長さ $ # 終了のアンカー", RegexOptions.IgnorePatternWhitespace); string[] testStrings = { "A1", "AA11", "AAA", "111", "a1", "@1", "あ1", "ABC123DEF", "1", "A 2B3", "" }; foreach (string s in testStrings) { if (regex.IsMatch(s)) { Console.WriteLine(s + "=true"); } else { Console.WriteLine(s + "=false"); } }
結果は以下のようになるはずです。
A1=true
AA11=true
AAA=false
111=false
a1=false
@1=false
あ1=false
ABC123DEF=true
1=false
A 2B3=false
=false上のコードは C# ですが、読めなければ以下のサイトで VB.NET に変換できます。
Convert C# to VB.NET
http://www.developerfusion.com/tools/convert/csharp-to-vb/- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
みなさん、親切丁寧なご返信をいただき深く感謝申し上げます。
わたしの書き方が悪く、混乱させてしまいました。
申し訳ございません。パスワードを登録してもらうツールを作成しておりまして、
そのルールが、・大文字のアルファベットと、数字のみで構成されること。
・アルファベット、数字とも最低1文字以上は入ること。
・4文字以上、8文字以内で構成されること。です。テキストボックスに入力された値をチェックする
Functionプログラムを組みたいと思った次第です。投稿メッセージ中の「出したい答え」はあくまで例として
記述いたしました。文面が未熟で申し訳ございませんでした。
どうかよろしくお願い申し上げます。- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
>>佐祐理 さま
ご返信ありがとうございます。
いえ、a (小文字) や、@ (記号) は入ってはいけません。
あくまで大文字のアルファベットと、数字のみです。
しかも英字と数字がそれぞれ1文字以上入っていないといけません。わたしの質問が悪いせいで、ご提示いただいたチェックパターンですと
例えば、AAAAa1 でも、True になってしまうようです。- 編集済み kei_chan_gt 2013年8月2日 9:36
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
>>aviator__ さま
ご返信ありがとうございます。
ご提示いただいたチェックパターンですと、
「AAA1」も、「AAAA」も、「1111」も、すべてFalse になってしまいました。「AAA1」のみTrue にしたいです。
私もAviator さんのチェックパターンでいいのかと思っていましたが
何がいけなかったのでしょうか?- 編集済み kei_chan_gt 2013年8月2日 9:34
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
- 編集済み kei_chan_gt 2013年8月2日 9:34
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
- 編集済み kei_chan_gt 2013年8月2日 9:33
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
どれが誰に対するレスなのか分からないです。
私の先のレスのサンプルは、スレッドの表題どおり「半角大文字アルファベットと、半角数字、それぞれ一文字以上含めば True」の条件で、後出しの「4文字以上、8文字以内で構成されること。」の条件と合いませんが、2文字で修正できるはずです。
- 編集済み SurferOnWww 2013年8月2日 4:44 一部追記
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
> 2文字でですか?本当ですか??
そういう言い方は避けた方がいいと思います。
ウソは言いません。先に紹介した「ASP.NET の正規表現」に目を通してください。
ここは Q&A サイトでなくフォーラムで、技術者同士の情報交換の場所だと自分は思っています。なので、コピペして動くようなコードを回答として求めておられるなら、自分はご期待にお応えできないかもしれません。
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
SurferOnWww さま
すみません。からかったつもりもバカにしたつもりもありません。
ましてや疑ったつもりでもございません。
ご気分を害されましたらお詫び申し上げます。2文字で直るとご教示を受けましたので、悩みまくっていた問題が
あと少しで解決できるのだと、うれしくてお聞き直しをしてしまった
次第です。文字だと感情がうまく伝えられませんね。
申し訳ございませんでした。がんばって勉強します。- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
gekka さま
おかげさまで、gekka さまよりご教示いただいたパターンマッチングで
行いたい処理を実現することができました。大変に感謝申し上げます。
また、補足でご記載いただいた二重否定の理由も大変に勉強になりました。
これからご教示いただいたパターンの解析を行い、勉強したいと思います。
本当にどうもありがとうございました。- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
すべての返信
-
このあたり ↓ を読むときっと答えが見つかると思います。
ASP.NET の正規表現
http://msdn.microsoft.com/ja-jp/library/ms972966.aspx正規表現での量指定子
http://msdn.microsoft.com/ja-jp/library/vstudio/3206d374.aspx- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
こんな?
Sub Main() Dim reg As New System.Text.RegularExpressions.Regex("^(?!(?!.{4,8}$))[0-9A-Z]*([0-9][A-Z]|[A-Z][0-9])+[0-9A-Z]*$") Dim ss As String() = {"A1", "1A", "AA1", "AAA", "111", "a1", "@1", "1A", "A1A", "1A1", "1a1", "@1"} For length As Integer = 3 To 9 For Each s As String In ss Dim s2 As String s2 = s.PadRight(length, "1"c) Console.WriteLine(s2 + vbTab + reg.IsMatch(s2).ToString()) s2 = s.PadRight(length, "A"c) Console.WriteLine(s2 + vbTab + reg.IsMatch(s2).ToString()) Next Next End Sub
2013/08/02 20:40 二重否定を使った理由の追記
回答が酷過ぎるとレスをもらいました。「サンプルコード付きで回答した」のが酷いのか、「正しくないコード」(動作検証してあります)だから酷いのか、「コードが汚い」から酷いのか、「二重否定を使った」のが酷いのか、…(以下略)、理由が読み取れなかったので、二重否定を使った理由だけは説明。正規表現の先読みには「正の先読み(?=○)」と「負の先読み(?!○)」があります。
ですが、使おうとする時に書き方を忘れることがよくあります。
そんな時は「負の先読み」だけ覚えておけば二重否定を使うことでどちらの機能も実現できます。
覚えておくことが半分になるなんてお得だよね?
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 編集済み gekkaMVP 2013年8月2日 11:49
- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
これをなんとか、AND または AndAldo を使って、一発で条件に合うパターンマッチングにする方法はございませんでしょうか?
たぶん正規表現そのもの問題ではないと思います。中学か高校の数学で習うはずのド・モルガンの法則とかその辺り、NotやAndAlsoを重ねたときに何がTrueになるのか、逆に欲しい条件にするにはどう組み合わせればいいのか、その辺りができていないだけだと思います。
その上で、パターンマッチングの質問として答えるならば、上記のややこしさ、考慮漏れなどもあるため、Regex.IsMatch()を1回で完了できるようパターンを記述することをお勧めします。
つまり、「半角大文字アルファベットと、半角数字、それぞれ一文字以上含めば True」を更に噛み砕いて理解することが重要です。
これを「全角大文字アルファベット1文字以上の後に半角数字1文字以上、または半角数字1文字以上の後に全角大文字アルファベット1文字以上」に読み替えることができれば表現できるはずです。ところで小文字や記号、全角文字が含まれていた場合はどうなってほしいのでしょうか。
- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
Private Function NewPasswordCheck(ByVal NewPass1 As String) As Boolean If NewPass1.Length < 4 OrElse NewPass1.Length > 8 Then MessageBox.Show("パスワードは4桁以上8桁以下で入力して下さい。" _ , "入力値エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Return False End If If System.Text.RegularExpressions.Regex.IsMatch(NewPass1, "^[0-9]+$") AndAlso _ System.Text.RegularExpressions.Regex.IsMatch(NewPass1, "^[A-Z]+$") Then Return True Else MessageBox.Show("パスワードには[数字]と[英字]がそれぞれ" & vbCrLf & "1文字ずつ以上含まれていなければなりません。" _ , "入力値エラー", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Return False End If End Function
元々の造りを踏襲して、こんな感じでも良い気がします。- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
いくらなんでもその正規表現は…二重否定入ってますし。好き放題書いていいのなら
"^(?:(?<upper>[A-Z])|(?<number>[0-9])|.){4,8}$(?(upper)|(?!))(?(number)|(?!))"
とか書けますけど、回答として提示するには酷過ぎると思います。
ところでサンプルに a1 や @1 があるということは、 aA1 や @A1 はTrueになるべきなのかな?
- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
コードを書いている回答者の方がおられますが、自分の意図する方向とちょっと違うようなので、自分のお勧めを具体的に書いておきます。
先のレスで紹介した「ASP.NET の正規表現」のページの「高度なトピック」のセクションに書いてある "ルックアラウンド処理" を利用するのが便利だと思います。
今回の問題では以下のような感じになると思います。
Regex regex = new Regex(@" ^ # 開始のアンカー (?=.*\d) # 数字が 1 文字必要 (?=.*[A-Z]) # 大文字が 1 文字必要 [A-Z0-9]{2,} # 大文字、数字 2 文字以上の長さ $ # 終了のアンカー", RegexOptions.IgnorePatternWhitespace); string[] testStrings = { "A1", "AA11", "AAA", "111", "a1", "@1", "あ1", "ABC123DEF", "1", "A 2B3", "" }; foreach (string s in testStrings) { if (regex.IsMatch(s)) { Console.WriteLine(s + "=true"); } else { Console.WriteLine(s + "=false"); } }
結果は以下のようになるはずです。
A1=true
AA11=true
AAA=false
111=false
a1=false
@1=false
あ1=false
ABC123DEF=true
1=false
A 2B3=false
=false上のコードは C# ですが、読めなければ以下のサイトで VB.NET に変換できます。
Convert C# to VB.NET
http://www.developerfusion.com/tools/convert/csharp-to-vb/- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
みなさん、親切丁寧なご返信をいただき深く感謝申し上げます。
わたしの書き方が悪く、混乱させてしまいました。
申し訳ございません。パスワードを登録してもらうツールを作成しておりまして、
そのルールが、・大文字のアルファベットと、数字のみで構成されること。
・アルファベット、数字とも最低1文字以上は入ること。
・4文字以上、8文字以内で構成されること。です。テキストボックスに入力された値をチェックする
Functionプログラムを組みたいと思った次第です。投稿メッセージ中の「出したい答え」はあくまで例として
記述いたしました。文面が未熟で申し訳ございませんでした。
どうかよろしくお願い申し上げます。- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
>>佐祐理 さま
ご返信ありがとうございます。
いえ、a (小文字) や、@ (記号) は入ってはいけません。
あくまで大文字のアルファベットと、数字のみです。
しかも英字と数字がそれぞれ1文字以上入っていないといけません。わたしの質問が悪いせいで、ご提示いただいたチェックパターンですと
例えば、AAAAa1 でも、True になってしまうようです。- 編集済み kei_chan_gt 2013年8月2日 9:36
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
>>aviator__ さま
ご返信ありがとうございます。
ご提示いただいたチェックパターンですと、
「AAA1」も、「AAAA」も、「1111」も、すべてFalse になってしまいました。「AAA1」のみTrue にしたいです。
私もAviator さんのチェックパターンでいいのかと思っていましたが
何がいけなかったのでしょうか?- 編集済み kei_chan_gt 2013年8月2日 9:34
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
- 編集済み kei_chan_gt 2013年8月2日 9:34
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
- 編集済み kei_chan_gt 2013年8月2日 9:33
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
どれが誰に対するレスなのか分からないです。
私の先のレスのサンプルは、スレッドの表題どおり「半角大文字アルファベットと、半角数字、それぞれ一文字以上含めば True」の条件で、後出しの「4文字以上、8文字以内で構成されること。」の条件と合いませんが、2文字で修正できるはずです。
- 編集済み SurferOnWww 2013年8月2日 4:44 一部追記
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
> 2文字でですか?本当ですか??
そういう言い方は避けた方がいいと思います。
ウソは言いません。先に紹介した「ASP.NET の正規表現」に目を通してください。
ここは Q&A サイトでなくフォーラムで、技術者同士の情報交換の場所だと自分は思っています。なので、コピペして動くようなコードを回答として求めておられるなら、自分はご期待にお応えできないかもしれません。
- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
SurferOnWww さま
すみません。からかったつもりもバカにしたつもりもありません。
ましてや疑ったつもりでもございません。
ご気分を害されましたらお詫び申し上げます。2文字で直るとご教示を受けましたので、悩みまくっていた問題が
あと少しで解決できるのだと、うれしくてお聞き直しをしてしまった
次第です。文字だと感情がうまく伝えられませんね。
申し訳ございませんでした。がんばって勉強します。- 回答としてマーク kei_chan_gt 2013年8月3日 5:13
-
gekka さま
おかげさまで、gekka さまよりご教示いただいたパターンマッチングで
行いたい処理を実現することができました。大変に感謝申し上げます。
また、補足でご記載いただいた二重否定の理由も大変に勉強になりました。
これからご教示いただいたパターンの解析を行い、勉強したいと思います。
本当にどうもありがとうございました。- 回答としてマーク kei_chan_gt 2013年8月3日 5:12
-
正規表現の先読みには「正の先読み(?=○)」と「負の先読み(?!○)」があります。
その論理で言うなら * や + なんか使わずに {0,} や {1,} と書けばいいですはずですがそうはしていません。また他人の書いたコードに (?=) や (?<=) 、 (?<!) が織り交ぜられていたらどうするのでしょう。結局、gekkaさんの至極個人的なコーディングルールであり、(初出時)他人に説明なしに勧められるものではないと思います。
ですが、使おうとする時に書き方を忘れることがよくあります。
そんな時は「負の先読み」だけ覚えておけば二重否定を使うことでどちらの機能も実現できます。
覚えておくことが半分になるなんてお得だよね? -
> 覚えておくことが半分になるなんてお得だよね?
そういわれると反論したくなるのですが、負の先読みを使うより、自分がサンプルに書いた正の先読みを使ったほうが可読性が高いと思うのですが。
どうしても負の先読みを使うのであれば、以下のようにしたほうがよさそうです。
Regex regex2 = new Regex(@" (?!^[0-9]*$) # 数字だけではない (?!^[A-Z]*$) # 大文字だけではない ^ # 開始のアンカー ([A-Z0-9]{4,8}) # 大文字または数字が 4 - 8 文字 $ # 終了のアンカー", RegexOptions.IgnorePatternWhitespace);
-
流れに乗って私の書いた正規表現も説明しておきます。
^ # 開始のアンカー
(?:
(?<upper>[A-Z]) # 大文字があればupperとして記憶
|
(?<number>[0-9]) # 数字があればnumberとして記憶
|
. # その他任意の文字。<<どうやらこれは余分だった模様>>
) {4,8} # 以上の条件の文字が4文字から8文字繰り返される
$ # 終了のアンカー
(?(upper) # ところでupperがあったかどうか
# あれば何もしない
|
(?!) # なければ失敗とする
)
(?(number) # 同じくnumberがあったかどうか
# あれば何もしない
|
(?!) # なければ失敗とする
)一見複雑だけど、一番素直な実装だとは思っています。