特定の文字以降を削除する方法はわかったのですが、さらに複数の条件を加えたところ、当方のスキルでは出来ない状態です。

現在VBScriptである特定の文字以降を削除する方法を考えております。
現在LEN関数などで、特定の文字以降を削除する方法はわかったのですが、
複数の条件を加えたところ、当方のスキルでは出来ない状態です。
以下の条件を満たせるサンプルスクリプトを作成いただけないでしょうか


■文字列操作内容


□文字列処理対象: 「テスト 第XX回」
□文字列処理後の姿: 「テスト」


※文字列処理対象内の「XX」は数字1から3桁の場合があります。
※文字列処理対象内の「第」の前のスペースは半角、全角を含みます。また複数のスペースがある場合も削除対象となります。




上記のように、文字列の中で「第」の後に「XX」という数字2桁(若しくは1桁)がきて、その次の文字が「回」だった場合に
「第」から後ろを削除するというものです。また削除する際に、「第」の前にスペースが存在した場合は
スペースも含め削除というものです。(スペースは半角、全角を含む。また複数のスペースがある場合も全て削除対象)


宜しくお願い致します。

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2012/01/31 23:50:56
  • 終了:2012/02/01 14:18:47

ベストアンサー

id:a-kuma3 No.1

a-kuma3回答回数4488ベストアンサー獲得回数18572012/02/01 00:09:38

ポイント300pt

こんな感じ。

    data = "テスト 第123回"
    Set re = CreateObject("VBScript.RegExp")
    re.Pattern = "^(.+)[  ]*第[0-9]+回"
    re.Global = True
    Set matches = re.Execute(data)
    result = matches(0).SubMatches(0)       ' これが "テスト" になってます

正規表現オブジェクトというものを使います。
re.Pattern に設定している文字列が正規表現です。
ちょっと分かりにくいですが、[ ] の中には、半角の空白と全角の空白が続けて書いてあります。



windofjuly さんの回答で、VBA じゃなくて VBScript だってことに、今さら、気が付きました。
といっても、ほとんどコードは同じなんですけど。

data = "お試しコードのテスト 第123回"
Set re = new RegExp                     ' VBA と、ここだけ違う。
re.Pattern = "^(.+)[  ]*第[0-9]+回"
re.Global = True
Set matches = re.Execute(data)
result = matches(0).SubMatches(0)       ' これが "テスト" になってます

WScript.echo result



追記です。

まだ動かしてないのですが、勉強がてらした3行が何をやってるか教えていただくと幸いです(ぐーぐる先生に聞いてみましたがどうもよくわからない。。)

おっちょこちょいな回答を書いた手前、分かる範囲であれば、何でも答えます (^^;

>re.Global = True

これは、Execute メソッドで、指定した正規表現が一致する個所を見つけたときに、
それ以降も検索するかどうかの指定です。
Global = True だと、一致するパターンが複数あるときに、全て探そうとします。
今回の場合には、True でも False でも、動作に違いが無いんですが、
対象の文字列が "お試しコードのテスト 第123回 (関東支部開催 第25回" のように、
複数繰り返されているような場合に、Execute メソッドの戻りの内容が変わってきます。

>Set matches = re.Execute(data)

正規表現 re.Pattern が表す内容を、文字列 data に対して実行して、検索した結果を返します。
検索結果は、Matches というコレクションになっています。

>result = matches(0).SubMatches(0) ' これが "テスト" になってます

Execute メソッドの戻り値である Matches コレクションは、文字列 data を検索した結果が入ってます。
Matches コレクションは、Match オブジェクトのコレクションです。
先程の、Global プロパティが True だと、要素数が2以上になる可能性があります。

Match オブジェクトが、検索して一致した結果を表しています。
Match オブジェクトは、以下のプロパティと、コレクションを持ちます。

  • FirstIndex プロパティ … 一致した箇所の先頭の文字位置
  • Length プロパティ … 一致した箇所の長さ
  • Value プロパティ … 一致した文字列
  • SubMatches コレクション … 正規表現の () に相当する部分に一致した文字列のコレクション


正規表現の説明からした方が良いでしょうね。
"^(.+)[  ]*第[0-9]+回" という正規表現を分解すると、

^文字列の先頭を表す
(.+)任意の文字「.」の一回以上の繰り返し「+」
()でくくってあるのは、後で使いたいから
[  ]*[  ]が、半角の空白、もしくは、全角の空白一文字で、「*」がゼロ回以上の繰り返し
そのまま「第」に当たります
[0-9]+半角の 0から 9までの文字のどれかの一回以上の繰り返し
そのまま「回」に当たります


この正規表現を "お試しコードのテスト 第123回" に対して実行すると、全体がマッチします。
一回だけ見つけられるので、matches の要素数は 1 で、そのひとつ目の Match では、

  • FirstIndex … 文字列の先頭から一致してますから、0 になります。
  • Length … 文字列全体が一致しているので 14 です(バイト数ではなく、文字数)。
  • Value … 文字列全体が一致しているので、"お試しコードのテスト 第123回" になります。

ここで、正規表現に () でくくった "(.+)" があるので、そこに一致する部分が SubMatches コレクションで取得できます。
() でくくった表現はひとつしかないので、SubMatches の要素数は1です。
そのひとつ目の内容は、文字列の先頭から、空白に続く「第」の前までが該当するので、
matches(0).SubMatches(0) は "お試しコードのテスト" になります。


もし複数の条件を追加しようとする場合は
「Set re」の部分を「re1」「re2」「re3」として
同じような処理を回すみたいなのが一番効率がいいのでしょうか
ちなみに追加したいのは以下です。


 ・第XX話
 ・#XX
 ・(XX)
 ・(XX)
 ・XX話
  
  ※スペースの条件も1つ目と同じです。
  ※XXは数字で大文字も含む

「数字で大文字」というのは、全角のことですよね。
こんな感じになります。

Sub re_test (data, re)
    Set matches = re.Execute(data)
    result = matches(0).SubMatches(0)       ' これが "テスト" になってます
    WScript.echo "'" & result & "' <-- '" & data & "'"
end sub

Set re = new RegExp
re.Pattern = "^([^  ]+)[  ]+[第#((]?[0-90-9]+[回話))]?"

re_test "お試しコードのテスト 第123話"      , re
re_test "お試しコードのテスト #123  あああ" , re
re_test "お試しコードのテスト  (123)"      , re
re_test "お試しコードのテスト (123)"      , re
re_test "お試しコードのテスト 123話"        , re
re_test "お試しコードのテスト 第456話"      , re
re_test "お試しコードのテスト #456  あああ" , re
re_test "お試しコードのテスト  (456)"      , re
re_test "お試しコードのテスト (456)"      , re
re_test "お試しコードのテスト 456話"        , re

正規表現を変えたのと、動作確認の部分をサブルーチンにしただけです。

追加された条件と合わせて考えると、数字の部分と、その前後に一文字付くかもしれない、ということになります。

数字の部分には、全角も含むということなので、[0-90-9]+ としました。

数字の前に付く文字は、四つあって、そのうちのどれかということで [第#((]? です。
"?" は、直前の表現が0回か1回、という意味です。
"第?" で、第がひとつ付くか、付かないか、という意味で、これを [ ] で複数指定してます。

数字の後に付く文字も、同様に [回話))]? としてます。

他12件のコメントを見る
id:a-kuma3

考え方を変えました。
微妙なパターンが多いので、それぞれを "|" でくっつけます。
対応してるのは、以下の六つ。

  • 第~回
  • 第~話
  • #~
  • (~)
  • (~)
  • ~話

これの前に「...」があれば削除。更に前に空白(含む、全角空白)を削除。

Sub re_test (data, re)
    result = re.Replace(data, "")
    WScript.echo "'" & result & "' <-- '" & data & "'"
end sub

Set re = new RegExp
're.Pattern = "[  ]*(「[^」]+」)?[第#((]?[0-90-9]+[回話))]?.*"
re.Pattern = "[  ]*(「[^」]+」)?(第[0-90-9]+回|第[0-90-9]+話|#[0-90-9]+|\([0-90-9]+\)|([0-90-9]+)|[0-90-9]+話).*$"

re_test "お試しコードのテスト 第123話"      , re
re_test "お試しコードのテスト #123  あああ" , re
re_test "お試しコードのテスト  (123)"      , re
re_test "お試しコードのテスト (123)"      , re
re_test "お試しコードのテスト 123話"        , re

re_test "お試しコードのテスト 第456話"      , re
re_test "お試しコードのテスト #456  あああ" , re
re_test "お試しコードのテスト  (456)"      , re
re_test "お試しコードのテスト (456)"      , re
re_test "お試しコードのテスト 456話"        , re
re_test "お試しコードのテスト  456"        , re

re_test "お試しコードのテスト  TESTX「テストメッセージ」#6"    , re
re_test "お試しコードのテスト  テストX「テストメッセージ」#6"  , re

実行結果。

'お試しコードのテスト' <-- 'お試しコードのテスト 第123話'
'お試しコードのテスト' <-- 'お試しコードのテスト #123  あああ'
'お試しコードのテスト' <-- 'お試しコードのテスト  (123)'
'お試しコードのテスト' <-- 'お試しコードのテスト (123)'
'お試しコードのテスト' <-- 'お試しコードのテスト 123話'
'お試しコードのテスト' <-- 'お試しコードのテスト 第456話'
'お試しコードのテスト' <-- 'お試しコードのテスト #456  あああ'
'お試しコードのテスト' <-- 'お試しコードのテスト  (456)'
'お試しコードのテスト' <-- 'お試しコードのテスト (456)'
'お試しコードのテスト' <-- 'お試しコードのテスト 456話'
'お試しコードのテスト  456' <-- 'お試しコードのテスト  456'
'お試しコードのテスト  TESTX' <-- 'お試しコードのテスト  TESTX「テストメッセージ」#6'
'お試しコードのテスト  テストX' <-- 'お試しコードのテスト  テストX「テストメッセージ」#6'
2012/02/02 16:06:09
id:gocnia3

すみません!連絡遅れました
最初の質問からだいぶ複雑化しても何度もお答えいただきありがとうございました!
僕もa-kuma3並にかけるように勉強しなければですね
まずは本を一通りやるか…

ありがとうございました!

2012/02/07 21:35:11

その他の回答(2件)

id:a-kuma3 No.1

a-kuma3回答回数4488ベストアンサー獲得回数18572012/02/01 00:09:38ここでベストアンサー

ポイント300pt

こんな感じ。

    data = "テスト 第123回"
    Set re = CreateObject("VBScript.RegExp")
    re.Pattern = "^(.+)[  ]*第[0-9]+回"
    re.Global = True
    Set matches = re.Execute(data)
    result = matches(0).SubMatches(0)       ' これが "テスト" になってます

正規表現オブジェクトというものを使います。
re.Pattern に設定している文字列が正規表現です。
ちょっと分かりにくいですが、[ ] の中には、半角の空白と全角の空白が続けて書いてあります。



windofjuly さんの回答で、VBA じゃなくて VBScript だってことに、今さら、気が付きました。
といっても、ほとんどコードは同じなんですけど。

data = "お試しコードのテスト 第123回"
Set re = new RegExp                     ' VBA と、ここだけ違う。
re.Pattern = "^(.+)[  ]*第[0-9]+回"
re.Global = True
Set matches = re.Execute(data)
result = matches(0).SubMatches(0)       ' これが "テスト" になってます

WScript.echo result



追記です。

まだ動かしてないのですが、勉強がてらした3行が何をやってるか教えていただくと幸いです(ぐーぐる先生に聞いてみましたがどうもよくわからない。。)

おっちょこちょいな回答を書いた手前、分かる範囲であれば、何でも答えます (^^;

>re.Global = True

これは、Execute メソッドで、指定した正規表現が一致する個所を見つけたときに、
それ以降も検索するかどうかの指定です。
Global = True だと、一致するパターンが複数あるときに、全て探そうとします。
今回の場合には、True でも False でも、動作に違いが無いんですが、
対象の文字列が "お試しコードのテスト 第123回 (関東支部開催 第25回" のように、
複数繰り返されているような場合に、Execute メソッドの戻りの内容が変わってきます。

>Set matches = re.Execute(data)

正規表現 re.Pattern が表す内容を、文字列 data に対して実行して、検索した結果を返します。
検索結果は、Matches というコレクションになっています。

>result = matches(0).SubMatches(0) ' これが "テスト" になってます

Execute メソッドの戻り値である Matches コレクションは、文字列 data を検索した結果が入ってます。
Matches コレクションは、Match オブジェクトのコレクションです。
先程の、Global プロパティが True だと、要素数が2以上になる可能性があります。

Match オブジェクトが、検索して一致した結果を表しています。
Match オブジェクトは、以下のプロパティと、コレクションを持ちます。

  • FirstIndex プロパティ … 一致した箇所の先頭の文字位置
  • Length プロパティ … 一致した箇所の長さ
  • Value プロパティ … 一致した文字列
  • SubMatches コレクション … 正規表現の () に相当する部分に一致した文字列のコレクション


正規表現の説明からした方が良いでしょうね。
"^(.+)[  ]*第[0-9]+回" という正規表現を分解すると、

^文字列の先頭を表す
(.+)任意の文字「.」の一回以上の繰り返し「+」
()でくくってあるのは、後で使いたいから
[  ]*[  ]が、半角の空白、もしくは、全角の空白一文字で、「*」がゼロ回以上の繰り返し
そのまま「第」に当たります
[0-9]+半角の 0から 9までの文字のどれかの一回以上の繰り返し
そのまま「回」に当たります


この正規表現を "お試しコードのテスト 第123回" に対して実行すると、全体がマッチします。
一回だけ見つけられるので、matches の要素数は 1 で、そのひとつ目の Match では、

  • FirstIndex … 文字列の先頭から一致してますから、0 になります。
  • Length … 文字列全体が一致しているので 14 です(バイト数ではなく、文字数)。
  • Value … 文字列全体が一致しているので、"お試しコードのテスト 第123回" になります。

ここで、正規表現に () でくくった "(.+)" があるので、そこに一致する部分が SubMatches コレクションで取得できます。
() でくくった表現はひとつしかないので、SubMatches の要素数は1です。
そのひとつ目の内容は、文字列の先頭から、空白に続く「第」の前までが該当するので、
matches(0).SubMatches(0) は "お試しコードのテスト" になります。


もし複数の条件を追加しようとする場合は
「Set re」の部分を「re1」「re2」「re3」として
同じような処理を回すみたいなのが一番効率がいいのでしょうか
ちなみに追加したいのは以下です。


 ・第XX話
 ・#XX
 ・(XX)
 ・(XX)
 ・XX話
  
  ※スペースの条件も1つ目と同じです。
  ※XXは数字で大文字も含む

「数字で大文字」というのは、全角のことですよね。
こんな感じになります。

Sub re_test (data, re)
    Set matches = re.Execute(data)
    result = matches(0).SubMatches(0)       ' これが "テスト" になってます
    WScript.echo "'" & result & "' <-- '" & data & "'"
end sub

Set re = new RegExp
re.Pattern = "^([^  ]+)[  ]+[第#((]?[0-90-9]+[回話))]?"

re_test "お試しコードのテスト 第123話"      , re
re_test "お試しコードのテスト #123  あああ" , re
re_test "お試しコードのテスト  (123)"      , re
re_test "お試しコードのテスト (123)"      , re
re_test "お試しコードのテスト 123話"        , re
re_test "お試しコードのテスト 第456話"      , re
re_test "お試しコードのテスト #456  あああ" , re
re_test "お試しコードのテスト  (456)"      , re
re_test "お試しコードのテスト (456)"      , re
re_test "お試しコードのテスト 456話"        , re

正規表現を変えたのと、動作確認の部分をサブルーチンにしただけです。

追加された条件と合わせて考えると、数字の部分と、その前後に一文字付くかもしれない、ということになります。

数字の部分には、全角も含むということなので、[0-90-9]+ としました。

数字の前に付く文字は、四つあって、そのうちのどれかということで [第#((]? です。
"?" は、直前の表現が0回か1回、という意味です。
"第?" で、第がひとつ付くか、付かないか、という意味で、これを [ ] で複数指定してます。

数字の後に付く文字も、同様に [回話))]? としてます。

他12件のコメントを見る
id:a-kuma3

考え方を変えました。
微妙なパターンが多いので、それぞれを "|" でくっつけます。
対応してるのは、以下の六つ。

  • 第~回
  • 第~話
  • #~
  • (~)
  • (~)
  • ~話

これの前に「...」があれば削除。更に前に空白(含む、全角空白)を削除。

Sub re_test (data, re)
    result = re.Replace(data, "")
    WScript.echo "'" & result & "' <-- '" & data & "'"
end sub

Set re = new RegExp
're.Pattern = "[  ]*(「[^」]+」)?[第#((]?[0-90-9]+[回話))]?.*"
re.Pattern = "[  ]*(「[^」]+」)?(第[0-90-9]+回|第[0-90-9]+話|#[0-90-9]+|\([0-90-9]+\)|([0-90-9]+)|[0-90-9]+話).*$"

re_test "お試しコードのテスト 第123話"      , re
re_test "お試しコードのテスト #123  あああ" , re
re_test "お試しコードのテスト  (123)"      , re
re_test "お試しコードのテスト (123)"      , re
re_test "お試しコードのテスト 123話"        , re

re_test "お試しコードのテスト 第456話"      , re
re_test "お試しコードのテスト #456  あああ" , re
re_test "お試しコードのテスト  (456)"      , re
re_test "お試しコードのテスト (456)"      , re
re_test "お試しコードのテスト 456話"        , re
re_test "お試しコードのテスト  456"        , re

re_test "お試しコードのテスト  TESTX「テストメッセージ」#6"    , re
re_test "お試しコードのテスト  テストX「テストメッセージ」#6"  , re

実行結果。

'お試しコードのテスト' <-- 'お試しコードのテスト 第123話'
'お試しコードのテスト' <-- 'お試しコードのテスト #123  あああ'
'お試しコードのテスト' <-- 'お試しコードのテスト  (123)'
'お試しコードのテスト' <-- 'お試しコードのテスト (123)'
'お試しコードのテスト' <-- 'お試しコードのテスト 123話'
'お試しコードのテスト' <-- 'お試しコードのテスト 第456話'
'お試しコードのテスト' <-- 'お試しコードのテスト #456  あああ'
'お試しコードのテスト' <-- 'お試しコードのテスト  (456)'
'お試しコードのテスト' <-- 'お試しコードのテスト (456)'
'お試しコードのテスト' <-- 'お試しコードのテスト 456話'
'お試しコードのテスト  456' <-- 'お試しコードのテスト  456'
'お試しコードのテスト  TESTX' <-- 'お試しコードのテスト  TESTX「テストメッセージ」#6'
'お試しコードのテスト  テストX' <-- 'お試しコードのテスト  テストX「テストメッセージ」#6'
2012/02/02 16:06:09
id:gocnia3

すみません!連絡遅れました
最初の質問からだいぶ複雑化しても何度もお答えいただきありがとうございました!
僕もa-kuma3並にかけるように勉強しなければですね
まずは本を一通りやるか…

ありがとうございました!

2012/02/07 21:35:11
id:windofjuly No.2

うぃんど回答回数2625ベストアンサー獲得回数11492012/02/01 00:23:09

ポイント40pt

正規表現を使います
vbsなら下記のような具合です

Option Explicit

' データ準備
Dim s1, s2
s1 = "テスト 第195回  "
s2 = ""

' 正規表現による置換
Dim r
Set r = New RegExp
r.Pattern = "(.*)[  ]*第[0-90-9]+回.*"
s2 = r.Replace(s1, "$1")

' 結果出力
WScript.Echo "[" & s2 & "]"

前後の空白を消せたかどうかの確認のため、結果出力では[角括弧]でくくってます

他2件のコメントを見る
id:windofjuly

a-kuma3 さんのは、
必要な部分だけを抜き出す手法です

私のは、
不要な部分を消し去るという手法です

Microsoftのデベロッパー向けのサイトに解説があるので読んでみると良いでしょう
http://msdn.microsoft.com/ja-jp/library/ms974570.aspx

2012/02/01 01:14:13
id:gocnia3

なるほど。実はぐーぐる先生にその頁をおしえてもらったのですが理解できませんでした。やはり自分でがりがりやんないとわからないままですね。。

ご回答ありがとうございました。

2012/02/01 12:51:28
id:oil999 No.3

oil999回答回数1728ベストアンサー獲得回数3202012/02/01 00:31:34

ポイント20pt

スクリプトを組んでみました。
元の文字列を変数sourに入れると、変数destに切り出したい文字列が入るようになっています。
もし元の文字列がルール通りでないと、destは空になります。

Option Explicit

Dim sour, dest
Dim re, remat

sour = "テスト  第123回"        '元の文字列

'正規表現パターンの設定
Set re = new RegExp
re.IgnoreCase = True
re.Global = True
re.pattern = "^(.+)([  ]+第[0-9]{1,3}回)$"
Set remat = re.Execute(sour)

'抽出
dest = ""
if (remat.Count = 1) Then
    dest = remat(0).SubMatches(0)
End If

Set re = Nothing

MsgBox dest    '表示
id:gocnia3

ご回答に感謝いたします。勉強になります

2012/02/01 12:48:55

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません