C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[1]: 正規表現の後読み


(過去ログ 164 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■94908 / inTopicNo.1)  正規表現の後読み
  
□投稿者/ OA (1回)-(2020/06/03(Wed) 11:18:34)

分類:[VB.NET/VB2005 以降] 

正規表現を勉強中です。環境はVB2019です。
以下のような正規表現は、どう表現すればいいか教えて下さい。

(1)開始文字列から始まって終了文字列で終わる。
(2)但し、その途中に開始文字列が現れたらパーサをその位置まで進めてマッチとしない。

(例)対象文字列:【0開始12開始34終了56開始78終了9】
【開始】で始まって【終了】で終わり、かつ、途中に【開始】が現れない。
最初の「開始12」の後に「開始」が現れるので、最初の開始12はスキップする。
否定後読みを使うのだと思うのですが【開始(?<!.*?開始).*?終了】だと何もマッチしません。

希望文字列:Matches(0)= 【開始34終了】
      Matches(1)= 【開始78終了】

以上のような正規表現パターンを教えてください。
引用返信 編集キー/
■94910 / inTopicNo.2)  Re[1]: 正規表現の後読み
□投稿者/ Hongliang (1043回)-(2020/06/03(Wed) 12:48:27)
開始(?:(?!開始).)*終了
とか。
引用返信 編集キー/
■94911 / inTopicNo.3)  Re[1]: 正規表現の後読み
□投稿者/ 魔界の仮面弁士 (2734回)-(2020/06/03(Wed) 12:54:58)
No94908 (OA さん) に返信
> (1)開始文字列から始まって終了文字列で終わる。
> (2)但し、その途中に開始文字列が現れたらパーサをその位置まで進めてマッチとしない。
> (例)対象文字列:【0開始12開始34終了56開始78終了9】

【開始34終了】【開始78終了】なら "開始(?:(?!開始).)*終了"
【開始12開始34終了】【開始78終了】なら "開始.*?終了"
【開始12開始34終了56開始78終了】なら "開始.*終了"

でどうでしょう。
引用返信 編集キー/
■94912 / inTopicNo.4)  Re[2]: 正規表現の後読み
□投稿者/ OA (2回)-(2020/06/03(Wed) 13:50:50)
2020/06/03(Wed) 13:54:04 編集(投稿者)

Hongliangさん、魔界の仮面弁士さん、 ありがとうございます。
まとめて返信させてください。

【開始(?:(?!開始).)*終了】で希望結果となりました。
完全に先読みと後読みを勘違いしてました。
唯、未だに理解できていないので、ご教示頂けないでしょうか?

パターン 【開始(?:(?!開始).)*終了】の中で自分が理解出来ているのは

(1)【開始】から始まって
(2)(?!開始)は否定先読みで先頭の【開始】の後に【開始】がない
(3)*終了 直前の0回以上の繰り返し【終了】で終わる(最長一致)

理解できないのは、
外カッコの (?:   .) ★ここが何をしているのか、わからない
(?:)はグループとしてキャプチャしないですよね?
恐縮ですが、解説をお願いできませんか?
引用返信 編集キー/
■94914 / inTopicNo.5)  Re[3]: 正規表現の後読み
□投稿者/ 魔界の仮面弁士 (2735回)-(2020/06/03(Wed) 14:32:12)
No94912 (OA さん) に返信
> 理解できないのは、
> 外カッコの (?:   .) ★ここが何をしているのか、わからない
> (?:)はグループとしてキャプチャしないですよね?

Groups が変化します。

Regex.Matches("0開始12開始34終了56開始78終了9", "開始(?:(?!開始).)*終了")
 Index= 5,Length= 6,Value=【開始34終了】,Groups=[開始34終了]
 Index=13,Length= 6,Value=【開始78終了】,Groups=[開始78終了]

Regex.Matches("0開始12開始34終了56開始78終了9", "開始((?!開始).)*終了")
 Index= 5,Length= 6,Value=【開始34終了】,Groups=[開始34終了][4]
 Index=13,Length= 6,Value=【開始78終了】,Groups=[開始78終了][8]

Regex.Matches("0開始12開始34終了56開始78終了9", "(開始(?:(?!開始).)*終了)")
 Index= 5,Length= 6,Value=【開始34終了】,Groups=[開始34終了][開始34終了]
 Index=13,Length= 6,Value=【開始78終了】,Groups=[開始78終了][開始78終了]

Regex.Matches("0開始12開始34終了56開始78終了9", "(開始)((?!開始).)*(終了)")
 Index= 5,Length= 6,Value=【開始34終了】,Groups=[開始34終了][開始][4][終了]
 Index=13,Length= 6,Value=【開始78終了】,Groups=[開始78終了][開始][8][終了]

Regex.Matches("0開始12開始34終了56開始78終了9", "(開始)(?:(?!開始).)*(終了)")
 Index= 5,Length= 6,Value=【開始34終了】,Groups=[開始34終了][開始][終了]
 Index=13,Length= 6,Value=【開始78終了】,Groups=[開始78終了][開始][終了]

引用返信 編集キー/
■94915 / inTopicNo.6)  Re[4]: 正規表現の後読み
□投稿者/ OA (3回)-(2020/06/03(Wed) 16:15:06)
No94914 (魔界の仮面弁士 さん) に返信

ありがとうございます。

(?:)については、なんとなく、理解できました。
(?:)は、やっぱりグループとしてキャプチャしない為なのですね。
でも、やっぱり自分一人ではこのパターンを構築できる自信がありません。
頭が悪いのか、ウニ状態に陥っています。

(?:)を外して、単純化すると【開始((?!開始).)*終了】

((?!開始).)の部分を日本語にすると
「【開始】の後に続く【開始】以外の任意の1文字をグループ化」
という認識で合ってますか? ★この認識がそもそも間違っている気がする

であれば、以下のGroups(1)が[4]と「8」の理由が理解できません。
[3]と「7」なら、なんとなく理解できるのですが・・・

頭が悪くて申し訳ありませんが、この際、ちゃんと理解したいので教えてて貰えないでしょうか?
後の*(直前の0回以上の繰り返し)が関与してるのでしょうか?

Regex.Matches("0開始12開始34終了56開始78終了9", "開始((?!開始).)*終了")
 Index= 5,Length= 6,Value=【開始34終了】,Groups=[開始34終了][4]
 Index=13,Length= 6,Value=【開始78終了】,Groups=[開始78終了][8]
引用返信 編集キー/
■94916 / inTopicNo.7)  Re[5]: 正規表現の後読み
□投稿者/ 魔界の仮面弁士 (2736回)-(2020/06/03(Wed) 20:32:00)
No94915 (OA さん) に返信
> [3]と「7」なら、なんとなく理解できるのですが・・・

自分も正規表現はさほど得意な方ではないのですが、この場合、
Groups(1) は『【開始】以外の任意の 1 文字なパターン』なので、"3" および "4" がキャプチャされますが、
末尾に進むにしたがって、キャプチャーグループが上書きされていくものと理解しています。


"開始((?!開始).)*終了" あるいは "開始(?:((?!開始).)*)終了" の場合、
Matches(0).Groups(1) は、.Captures(*).Value = { "3", "4" }、.Value = "4"
Matches(0).Groups(0) は、.Captures(*).Value = { "開始34終了" }、.Value = "開始34終了"

"開始(((?!開始).)*)終了" の場合、
Matches(0).Groups(2) は、.Captures(*).Value = { "3", "4" }、.Value = "4"
Matches(0).Groups(1) は、.Captures(*).Value = { "34" }、.Value = "34"
Matches(0).Groups(0) は、.Captures(*).Value = { "開始34終了" }、.Value = "開始34終了"

"開始((?:(?!開始).)*)終了" の場合
Matches(0).Groups(1) は、.Captures(*).Value = { "34" }、.Value = "34"
Matches(0).Groups(0) は、.Captures(*).Value = { "開始34終了" }、.Value = "開始34終了"

"(開始)(?:(?!\1).)*終了" の場合
Matches(0).Groups(1) は、.Captures(*).Value = { "開始" }、.Value = "開始"
Matches(0).Groups(0) は、.Captures(*).Value = { "開始34終了" }、.Value = "開始34終了"
引用返信 編集キー/
■94917 / inTopicNo.8)  Re[6]: 正規表現の後読み
□投稿者/ 魔界の仮面弁士 (2737回)-(2020/06/03(Wed) 20:42:10)
No94916 (魔界の仮面弁士) に追記
> 末尾に進むにしたがって、キャプチャーグループが上書きされていくものと理解しています。

https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/alternation-constructs-in-regular-expressions

上記で使われている例文でいえば:

Regex.Matches("Yes. This dog is very friendly.", "((\w+)[\s.])+")

Matches(1).Groups(2) は、.Captures(*).Value = { "This", "dog", "is", "very", "friendly" }、.Value = "friendly"
Matches(1).Groups(1) は、.Captures(*).Value = { "This", "dog", "is", "very", "friendly." }、.Value = "friendly."
Matches(1).Groups(0) は、.Captures(*).Value = { "This dog is very friendly." }、.Value = "This dog is very friendly."
Matches(1) は .Value = "This dog is very friendly."
Matches(0).Groups(2) は、.Captures(*).Value = { "Yes" }、.Value = "Yes"
Matches(0).Groups(1) は、.Captures(*).Value = { "Yes." }、.Value = "Yes."
Matches(0).Groups(0) は、.Captures(*).Value = { "Yes." }、.Value = "Yes."
Matches(0) は .Value = "Yes."
引用返信 編集キー/
■94918 / inTopicNo.9)  Re[7]: 正規表現の後読み
□投稿者/ OA (4回)-(2020/06/04(Thu) 06:50:18)
No94917 (魔界の仮面弁士 さん) に返信

御教示、感謝します。

Groupの下にCaptureCollectionがあるのですね。
Matches=>Match=>Groups=>Groupまでしか使った事がなく
CaptureCollectionクラスやCaptureクラスの存在を初めて知りました。

魔界の仮面弁士さんが書かれている通りCaptureCollectionを列挙してみて、確かに
Matches(0).Groups(1)のCapturesは { "3", "4" }となっている事を確認しました。
【((?!開始).)】は【3】もテストにはパスしているが最長一致となる【4】が最終的な
Group.Valueになると。このように理解する事とします。
この程度の前後読み位はスラスラ書けるように精進します。

この度は大変お世話になり、どうもありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -