
正規表現は苦手なもので、すみませんが教えてください。
下のサンプルで、マッチングに "[(|(].*?[)|)]$"を指定すれば、最後から最短の()内を取得できるものと期待していましたが、実行してみると最短の「(c)」ではなく「(a)x(b)y(c)」がマッチしてしまうようです。
$を除いて"[(|(].*?[)|)]"と"[(|(].*[)|)]"で実行してみると、ちゃんと違いがあるのですが…
$をつけた場合で最短の表記方法は、どのようにすればよいのでしょうか?
Sub sample()
Dim RegE, RegMc
Dim str1 As String, str2 As String
Set RegE = CreateObject("VBScript.RegExp")
str1 = "test(a)x(b)y(c)"
str2 = ""
RegE.Pattern = "[(|(].*?[)|)]$"
Set RegMc = RegE.Execute(str1)
If RegMc.Count > 0 Then
str2 = RegMc(0).Value
str1 = RegE.Replace(str1, "")
End If
MsgBox (str1 & vbLf & str2)
End Sub
No.3ベストアンサー
- 回答日時:
こんばんは。
こんな感じかな?
>"[(|(].*?[)|)]$"
VBScript の正規表現には、.*? の「最短マッチ」がなかったと思います。あれば、私は苦労しなかったと思います。それで、タイプライブラリを入れて、BRegExp なんていうものを代用したりするわけですが、他人の環境では強要できません。そうすると、他は、やはり、InstrRev などを使って取り出して使うことになってしまいます。
今回は、仕方がないので、中に入れる文字を特定して、マッチする部分を区分けしなければいけません。
\w+ の場合は、数字、アルファベット、アンダーバーに限ります。
[ぁ-龠]+ なら、全角文字です。
それと、私が書くパターンは、最後尾の$を用いずに、(a) を数えて、その最後を出すという方法を取ります。
以下のコードの部分を変えます。
Pattern = "[\((]\w+[)\)]" 'パターン
str2 = RegMc(RegMc.Count - 1) '抽出
'------------------------
Sub sample1()
Dim RegMc As Variant
Dim str1 As String
Dim str2 As String
str1 = "test(a)x(b)y(c)"
str2 = ""
With CreateObject("VBScript.RegExp")
.Pattern ="[\((]\w+[)\)]$" 'パターン
.Global = True
Set RegMc = .Execute(str1)
If RegMc.Count > 0 Then
str2 = RegMc(0) '抽出
End If
MsgBox (str1 & vbLf & str2)
End With
End Sub
この回答への補足
回答ありがとうございます。
関係のないつもりでいた、"[(|(]"部分も訂正いただき恐縮です。(やっぱり苦手)
>VBScript の正規表現には、.*? の「最短マッチ」がなかったと思います
最初にそう思って、「最後尾」の$をとってテストして見たところ、「.*」では「(a)e(b)f(c)」が、「.*?」では「(a)」、「(b)」、「(c)」それぞれがマッチするので、わからなくなった次第です。(MS得意の仕様なのかなぁ?)
>最後尾の$を用いずに、(a) を数えて、その最後を出すという方法を
>取ります。
これだと、最後尾ということを別途判定する必要がでてきますね。
でも、いいヒントをいただきましたので、明日、研究してみます。
No.7
- 回答日時:
こんにちは。
一応、自分の描いていたものをコード化してみました。
>句読点、「(1)」「々」などの使いそうな文字もはねられてしまうので、範囲を段々広げてみたりもしましたが
カッコの中に、カッコがある場合に、除外するようにしてみました。
Const SRC As String = "(株),(財),(a)" '検索語
Const REP As String = "α,β,γ" '臨時の置換語
このように臨時に置き換えます。参考にしてみてください。もし、分からない部分がありましたら、新たに質問を出してください。
'----------------------------------------------------
Const SRC As String = "(株),(財),(a)" '検索語
Const REP As String = "α,β,γ" '臨時の置換語
'SRC と REP の数は、必ず揃えてください。
Sub Test1()
Dim str1 As String
Dim ret As String
str1 = "test(a)x(b)y(c(a))"
ret = rePickUp(str1)
MsgBox str1 & vbCrLf & ret
End Sub
Function rePickUp(mTxt As String)
Dim Matches As Object
Dim rTxt As String
Dim i As Integer
mTxt = RepW(mTxt, False)
With CreateObject("VBScript.RegExp")
.Pattern = "\([^\)]+\)"
.Global = True
Set Matches = .Execute(mTxt)
i = Matches.Count
If i > 0 Then
rTxt = Matches(i - 1)
End If
End With
rTxt = RepW(rTxt, True)
rePickUp = rTxt
End Function
Function RepW(mTxt As String, Optional flg As Boolean = False)
Dim i As Integer
Dim oTxt As String
Dim ret As String
Dim wdRep1 As Variant
Dim wdRep2 As Variant
wdRep1 = Split(SRC, ",")
wdRep2 = Split(REP, ",")
oTxt = Replace(mTxt, ")", ")", 1)
oTxt = Replace(oTxt, "(", "(", 1)
If flg = False Then
For i = 0 To UBound(wdRep1)
ret = Replace(oTxt, wdRep1(i), wdRep2(i))
Next i
Else
For i = 0 To UBound(wdRep1)
ret = Replace(oTxt, wdRep2(i), wdRep1(i))
Next i
End If
RepW = ret
End Function
締め切りが早すぎたようで、申し訳ありません。
一時置換ですね。
時々、同様の方法を使わせていただいています。
私の場合は、入力できない文字(ESCなど+連番とか)を利用することが多いですが…
今回は、入力文そのものは入力者の整理方法にまかせている部分が多いので、どのような2重括弧があるのか(ないのか)想定するのが難しいのと、似たような(似ていて違う)マッチングを他にも何種類かやっているので、一つの処理はできるだけ簡単に済ませてしまいたいという気持ちもありました。
全体としてはリトライ可能な処理なので、使用者が「えっ!なんで?」と思うような誤解釈を生じない範囲であれば、完全性はそれほど追求しなくても良いという部分もありました。(より良いに越したことはありませんが)
わざわざ、追加の回答をいただきありがとうございました。
No.6
- 回答日時:
こんにちは。
>全角英数や句読点、「(1)」「々」などの使いそうな文字もはねられてしまうので、
#4のレスを読みましたが、本格的に作るとなると、作り直さないといけないように思います。VBAというよりは、正規表現や文字処理も問題です。実際の文字列を見て、パターン自体を考え直さないといけないような気がします。あまり単純な方法ではできないかもしれません。もともと、VBA内は、Unicode ですから、JISのように一括でできるわけではなく、リストが分散しています。
例:"[\u2421-\u2473\u2521-\u2576\uFF66-\uFF9F0-9A-z]+
>VBA内は、Unicode ですから、JISのように一括でできるわけではなく
今まであまり意識してはいませんでしたが、[ぁ-龠]+から範囲を拡張しようとして、どうやらUnicodeらしいことは確認していました。
>例:"[\u2421-\u2473\u2521-\u2576\uFF66-\uFF9F0-9A-z]+
これに似たようなことをやってたのですが、いっそのこと「()以外で」という考えに至ったわけです。(最短の意味では「)以外」が正しいのかも)
いろいろお付き合いいただき、大変ありがとうございました。
No.5
- 回答日時:
こんにちは。
もともと最短マッチは、一番先に見つけていたものに対して、最短距離のものを引き出すわけですから、意味が違いますね。今回、(a) (b) (c) の数が決まらないとすれば、しばらく考えてみましたが、以下の方法を考えてみました。ここの掲示板の常連さんたちが考えるパターンのような気がします。(笑)
全角、半角の問題が少し見にくくなりますから、Replace を使ったらどうでしょうか。(これは私が良く使うパターン)いずれにしても、実務的には、最終的には、統一するのではないでしょうか?
"[\((][^\((]+[)\)]"
↓
"\([^\)]+\)"
Sub sample2()
Dim RegMc As Variant
Dim i As Integer
Dim str1 As String
Dim str2 As String
str1 = "test(a)x(b)y(ccccaa)" '←全角が入っています
str1 = Replace(str1, "(", "(", , , 1)
str1 = Replace(str1, ")", ")", , , 1)
str2 = ""
With CreateObject("VBScript.RegExp")
.Pattern = "\([^\)]+\)"
.Global = True
Set RegMc = .Execute(str1)
i = RegMc.Count
If i > 0 Then
str2 = RegMc(i - 1)
End If
MsgBox (str1 & vbCrLf & str2)
End With
End Sub
正規表現を使わない方法
(私が実際に書く方法です。RegExp は、オブジェクトを最初に作っておくか、参照設定するなら良いのですが、インスタンスが生成されますから、もし、短い期間なら、VB関数で処理してしまいます。ネット検索では、こちらの方が速いようです。複雑なものには向いていません。)
Sub sample3()
Dim RegMc As Variant
Dim i As Integer
Dim j As Integer
Dim str1 As String
Dim str2 As String
str1 = "test(a)x(b)y(ccccaa)" '←全角が入っています
str2 = ""
i = InStrRev(str1, "(", , 1) '1...TextCompare
j = InStr(i, str1, ")", 1)
If i > 0 And j > 0 Then
str2 = Mid$(str1, i, j - i + 1)
End If
MsgBox str1 & vbCrLf & str2
End Sub
私は、この種のマクロが一番多いのに、少しも覚えないですね。(^^;Perlの勉強を辞めてしまったからですが。
>半角の問題が少し見にくくなりますから、Replace を使ったらどうでしょうか。
これは処理が簡単になることもあり、頭の片隅にはありましたが、入力者のミスの場合はOKですが、意図的に使い分けている可能性も考慮すると、使わないですむならそれに越したことはないと考えていました。
>実務的には、最終的には、統一するのではないでしょうか?
ん~、そうですね。 「行末に(…)がある場合は、○○の意味とする」などのルールも同時に決めているので、ルールの方で半角( )のみに限定してしまうとかするほうがいいのかなと考えているところです。
(あくまでも、入力文は尊重してあげようと…)
>"\([^\)]+\)"
「最短」の意味からは、[ ]内は)のみでOKなのですが、$を付けた場合、パターンの先頭からが優先されるのか、後ろからが優先されるのかよくわからなかったので… ( 実験してみろって? すんません。)
まぁ、当初は考慮していなかった2重括弧の場合なども考えてしまったりしたこともあるのですが。(当初の質問の最短とはズレてきてますが…)
>正規表現を使わない方法
なるほど。 プリミティブですが正規表現などで悩まずにすみますね。(笑)
今回は同じ文章に対して、何種類かのマッチングでテストして、文章の構成と解釈を決めていることもあったので、はなからパターンだけで処理できる正規表現に走っていました。
速度も速いとのことですので、覚えておきます。
いろいろ、追加情報をありがとうございました。
No.4
- 回答日時:
#3 の補足の部分
>関係のないつもりでいた、"[(|(]"部分も訂正いただき恐縮です。
\( も ( も両方とも行けるようでしたが、なんとなく、違っていたような気がしました。 | は、その左右が、二文字以上で、文字列を( ) で括った場合に、その文字列どちらかになる、ということだったと思います。この場合は、どちらでも同じです。
VBScript の正規表現は、簡単なようでも、逆に、標準ではありません。Perl 標準のものを出してほしいものですね。
他は、また、見てみます。
この回答への補足
お礼を書いちゃったので、補足に追加ですが、
おまじない程度に2重括弧までを考慮して、こんなところかなと考えています。
"[\((](([\((][^\(\)()]+[)\)])|[^\(\)()])+[)\)]$"
補足への解説まで、わざわざありがとうございます。
>| は、その左右が、二文字以上で、文字列を( ) で括った場合に、
>その文字列どちらかになる
うっかり混同して、[ ]の中で使ってしまってました。
そこまで見通して訂正していただいていたので、恐縮した次第です。
対象が自由入力文字列なので、入力可能な文字は極力そのまま通したいというのがやっかいなところです。(事前に「(」→「(」や半角英数などへの変換をしておけば、少しは簡単になるのですが…)
おまけに、似たようなマッチングを数種類行っているので。
さて、教えて頂いた[ぁ-龠]+だと全角英数や句読点、「(1)」「々」などの使いそうな文字もはねられてしまうので、範囲を段々広げてみたりもしましたが、最終的に、()以外の文字の繰り返しを許すということで、
"[\((][^\(\)()]+[)\)]$" というパターンでどうやらうまくいきそうです。(最後尾判定もできているみたい)
これでも、()内に(株)みたいなのが入っていると、はねてしまうのですが、まぁしかたがないかと。(これ以上は、私には荷が重いので)
一時は、"[)\)]$"にマッチした場合で、"[\((].*?[)\)]"にマッチする最終のものという2段階方式でもしかたないかと思っていたのですが、なんとかなりそうです。
いろいろとお知恵を、ありがとうございました。
No.2
- 回答日時:
#1です。
もしかして
str1 = "test(a)x(b)y(c)abcd"
でも最後尾の(c)を取得したいなら、
Sub sample()
Dim RegE, RegMc
Dim str1 As String, str2 As String
Set RegE = CreateObject("VBScript.RegExp")
str1 = "test(a)x(b)y(c)abcd"
str2 = ""
RegE.Pattern = "\(.?\)"
RegE.Global = True
Set RegMc = RegE.Execute(str1)
MsgBox RegMc.Item(RegMc.Count - 1)
End Sub
こんな感じとか?
いろいろ気を回していただき、大変恐れ入ります。
今回は、このケースではありません。 >最後尾
No1の回答のケースでOKなんですが…
No.1
- 回答日時:
最短とは最後尾で良いのでしょうか?
Sub sample()
Dim RegE, RegMc
Dim str1 As String, str2 As String
Set RegE = CreateObject("VBScript.RegExp")
str1 = "test(a)x(b)y(c)"
str2 = ""
RegE.Pattern = "\(.?\)$"
MsgBox RegE.Execute(str1)(0)
Stop
Set RegMc = RegE.Execute(str1)
If RegMc.Count > 0 Then
str2 = RegMc(0).Value
str1 = RegE.Replace(str1, "")
End If
MsgBox (str1 & vbLf & str2)
End Sub
こうゆう事とは違いますか?
回答ありがとうございます。
>最後尾で良いのでしょうか?
はい。最後尾のつもりです。
確かに、「.?」だと「(c)」はマッチするのですが、()内に複数文字列があるので(例では1文字でしたが…)、「(cd)」がマッチしなくなるため、「.*?」としていました。
でも、No3様の情報を見ると、どうやらダメみたいですね…
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) VBAで最新のデータを別シートに転記する方法をお教えください。 3 2022/04/07 19:20
- Visual Basic(VBA) ワークブック内すべて検索 2 2022/12/20 20:13
- Visual Basic(VBA) 2つのシートの任意のセルの番号が一致したら、一致した行をコピーする VBA 2 2023/06/19 20:48
- Visual Basic(VBA) Worksheet_Change 4 2023/03/12 21:54
- Visual Basic(VBA) countifsについての質問 3 2023/03/08 13:45
- Visual Basic(VBA) select caseの入れ子 3 2023/03/08 18:48
- Visual Basic(VBA) VBAで時間(00:00形式)を積算(足し算)したい 1 2022/11/15 17:04
- Visual Basic(VBA) VBAが止まります。 3 2022/08/31 14:09
- Visual Basic(VBA) 別シートから年齢別の件数をカウントしたいの続き 5 2023/01/24 00:16
- Visual Basic(VBA) ワークシートチェンジで曜日を表示する方法 1 2023/03/04 21:51
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
クラスの男子が「ドピュドピュ...
-
漫画の単行本は、発売日の一日...
-
大事な本を黄色の斑点から守る...
-
慢・漫の使い方について教えて...
-
友人などに借りた本がつまらな...
-
マンガ という言葉
-
漫画を読むことって読書ってい...
-
NTR系やレイプ系の漫画見て不安...
-
絵師はなぜ1枚絵ばかりで漫画...
-
高校生男子って、好きな女の子...
-
漫画アプリで、あなたへのおす...
-
介護士に美人や可愛い子は多い...
-
「生きらいでか」とはどういう...
-
少女漫画ってどうしてあんなに...
-
女子なのにhな画像や漫画を見る...
-
めちゃコミックのあなたの閲覧...
-
「~なんです」という言葉を文...
-
うまい返し方を教えてください。
-
するしない・・・
-
本屋さんなどで漫画が売り切れ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
漫画の単行本は、発売日の一日...
-
クラスの男子が「ドピュドピュ...
-
うまい返し方を教えてください。
-
妻がHな漫画を読んでいます
-
漫画を読むことって読書ってい...
-
数量のあらわし方
-
セブンネットプリントでPDFをプ...
-
絵師はなぜ1枚絵ばかりで漫画...
-
「~なんです」という言葉を文...
-
マンガ という言葉
-
昭和29年の10万円は今どのくら...
-
慢・漫の使い方について教えて...
-
口のでかい(特徴的な)キャラク...
-
高校生男子って、好きな女の子...
-
本屋さんなどで漫画が売り切れ...
-
観たり読み終わったりしたあと...
-
本気と書いてマジと読む
-
女子なのにhな画像や漫画を見る...
-
初音ミクの一人称って・・・
-
介護士に美人や可愛い子は多い...
おすすめ情報