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

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

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

Re[1]: VBの置換について。ひとつだけ置換は・・・できない??


(過去ログ 76 を表示中)

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

■44652 / inTopicNo.1)  VBの置換について。ひとつだけ置換は・・・できない??
  
□投稿者/ やまり (1回)-(2009/12/15(Tue) 00:55:32)

分類:[.NET 全般] 

畏れ入ります。

VB.NETの勉強をしております。

文字列の置換なのですが、ちょっと思いついたことがあって、簡単に実現できるかと思いきや・・・
できずに恥ずかしながら質問いたします。

<<やりたいこと>>

「これ」にマッチしたどれかひとつを「あれ」に変換したい。

フォーム1・・・入力例「これとこれとこれとこれ」
フォーム2・・・出力例「これとあれとこれとこれ」


---------------
あまりいい例が思いつかず、わかりにくい例で申し訳ありません。
もう少し書くとやりたいことは
・文字列の置換
・検索文字列は複数あり、そのうちひとつだけを置換

いろいろ考えて、まずは(1)(2)・・のように置換する方法を思いつきました。


「これとこれとこれとこれ」

「(1)と(2)と(3)と(4)」
↓(1)〜(4)のうちどれかをランダムで→「あれ」に置換
「(1)と(2)とあれと(4)」
↓残った(\d)を「これ」で置換しなおす。
「これとこれとあれとこれ」

しかし、VBのreplaceは「すべてを置換」してしまうのですね・・・
javaだとreplaceallと分かれているのですけど・・・・

なんだか自分でも考えすぎているような気がしています。


・もっと簡単なロジックで実現できそうでしょうか?
・マッチした文字列一つ目だけを置換、はできないのでしょうか?


引用返信 編集キー/
■44653 / inTopicNo.2)  Re[1]: VBの置換について。ひとつだけ置換は・・・できない??
□投稿者/ やまり (2回)-(2009/12/15(Tue) 01:06:57)
自己レスです

http://msdn.microsoft.com/ja-jp/library/system.text.regularexpressions.regex.replace(VS.80).aspx

Regex.Replace (String, String, Int32) 指定した入力文字列内で正規表現パターンに一致する文字列を、指定した最大回数だけ、指定した置換文字列に置換します。


のようにありました。
3つ目の引数に1を指定すればいいのでしょうか・・・?

これでできればなんとか強引にできそうですが

できればもっとシンプルに「○番目のマッチを置換」みたいなことができるとうれしいのですが。。。
引用返信 編集キー/
■44654 / inTopicNo.3)  Re[2]: VBの置換について。ひとつだけ置換は・・・できない??
□投稿者/ やまり (3回)-(2009/12/15(Tue) 01:45:50)
もうひとつ自己レスです。

perlでは$`と$'で前後が取れるようです。

#!/usr/bin/perl

my $a="ababab";
my $cnt=0;

print $a . "\n";
while( $a =~ /(a)/g ){
print qq($cnt : $1\t$`\t$'\n);
$cnt++;
}

こんな風にすると、まっちした前と後が$` $' にはいっているので
その値を使って2番目にマッチ、とかできそうです。

VB.NETでこの「$` $'」にあたるものは無いでしょうか・・・

引用返信 編集キー/
■44655 / inTopicNo.4)  Re[3]: VBの置換について。ひとつだけ置換は・・・できない??
□投稿者/ gtk2k (138回)-(2009/12/15(Tue) 02:44:14)
Dim strSrc As String = "これとこれとこれとこれ"
Dim strMatch As String = "これ"
Dim strReplace As String = "あれ"
とした場合

Dim rnd As New Random()
Dim ms As MatchCollection = Regex.Matches(strSrc, strMatch)
Dim idx As Integer = Rnd.Next(ms.Count)
Dim strDst As String = strSrc.Substring(0, ms(idx).Index) & strReplace & strSrc.Substring(ms(idx).Index + strMatch.Length)

でとりあえずできる(strDstが結果)。


引用返信 編集キー/
■44659 / inTopicNo.5)  Re[1]: VBの置換について。ひとつだけ置換は・・・できない??
□投稿者/ 魔界の仮面弁士 (1419回)-(2009/12/15(Tue) 09:30:22)
2009/12/15(Tue) 10:09:41 編集(投稿者)

No44652 (やまり さん) に返信
> しかし、VBのreplaceは「すべてを置換」してしまうのですね・・・
> ・マッチした文字列一つ目だけを置換、はできないのでしょうか?
Dim Src As String = "これとこれとこれとこれ"
Dim Ret As String = Replace(Src, "これ", "あれ", Count:=1)
とすれば、1 つだけ置換もできますよ。
Start:=x で、検索開始位置を調整することもできます。

3 つ目だけを置換したいなら、
 Ret = Replace(Replace(Src, "これ", "あれ", Count:=3), "あれ", "これ", Count:=2)
とか。汎用的ではありませんし、文字列によっては使えませんけれども。

汎用的にするなら、gtk2k さんの方法かな。


No44653 (やまり さん) に返信
> できればもっとシンプルに「○番目のマッチを置換」みたいなことができるとうれしいのですが。。。
その前に、マッチする文字列が○個以上存在するかをチェックする必要がありそうですね。
事前チェック無しで良いなら、こういう書き方も出来ますけれども。(VB2008)

'Imports System.Threading
'Imports System.Text.RegularExpressions

'3個目の「これ」を「あれ」にする。
Dim n As Integer = 0 '置換回数カウント用
Dim ret As String = Regex.Replace("これとこれとこれとこれ", "これ", Function(sz) If(Interlocked.Add(n, 1) = 3, "あれ", "これ"))
引用返信 編集キー/
■44671 / inTopicNo.6)  Re[4]: VBの置換について。ひとつだけ置換は・・・できない??
□投稿者/ やまり (4回)-(2009/12/15(Tue) 16:10:26)
gtk2kさん ご回答ありがとうございます。

やっぱりちょっと考えすぎてしまったようです。とても勉強になります汗


MatchCollection の使い方がまだ良くわからないのですが、
countメソッドで、「何番目」というのが取れるのですね・・・

むりに正規表現を使わない方がわかりやすいですね。

もう少しじっくりソースを見させて頂きたいと思います。。。



No44655 (gtk2k さん) に返信
> Dim strSrc As String = "これとこれとこれとこれ"
> Dim strMatch As String = "これ"
> Dim strReplace As String = "あれ"
> とした場合
>
> Dim rnd As New Random()
> Dim ms As MatchCollection = Regex.Matches(strSrc, strMatch)
> Dim idx As Integer = Rnd.Next(ms.Count)
> Dim strDst As String = strSrc.Substring(0, ms(idx).Index) & strReplace & strSrc.Substring(ms(idx).Index + strMatch.Length)
>
> でとりあえずできる(strDstが結果)。
>
>
引用返信 編集キー/
■44672 / inTopicNo.7)  Re[2]: VBの置換について。ひとつだけ置換は・・・できない??
□投稿者/ やまり (5回)-(2009/12/15(Tue) 16:15:21)
魔界の仮面弁士さん ありがとうございます。


MSDNも眺めたのですが、Count:= でなんばんめ、というのが取れるのを読み取れませんでした・・・

> Start:=x で、検索開始位置を調整することもできます。

そんなこともできるんですね。これも使えそうですね。


> Function(sz) If(Interlocked.Add(n, 1) = 3

これがちょっとどういう意味かわからないので、もうすこしじっくり見させていただきたいと思います。

とっても、感謝です。とりあえず、なんとか出来そうです!!





No44659 (魔界の仮面弁士 さん) に返信
> 2009/12/15(Tue) 10:09:41 編集(投稿者)
>
> ■No44652 (やまり さん) に返信
>>しかし、VBのreplaceは「すべてを置換」してしまうのですね・・・
>>・マッチした文字列一つ目だけを置換、はできないのでしょうか?
> Dim Src As String = "これとこれとこれとこれ"
> Dim Ret As String = Replace(Src, "これ", "あれ", Count:=1)
> とすれば、1 つだけ置換もできますよ。
> Start:=x で、検索開始位置を調整することもできます。
>
> 3 つ目だけを置換したいなら、
>  Ret = Replace(Replace(Src, "これ", "あれ", Count:=3), "あれ", "これ", Count:=2)
> とか。汎用的ではありませんし、文字列によっては使えませんけれども。
>
> 汎用的にするなら、gtk2k さんの方法かな。
>
>
> ■No44653 (やまり さん) に返信
>>できればもっとシンプルに「○番目のマッチを置換」みたいなことができるとうれしいのですが。。。
> その前に、マッチする文字列が○個以上存在するかをチェックする必要がありそうですね。
> 事前チェック無しで良いなら、こういう書き方も出来ますけれども。(VB2008)
>
> 'Imports System.Threading
> 'Imports System.Text.RegularExpressions
>
> '3個目の「これ」を「あれ」にする。
> Dim n As Integer = 0 '置換回数カウント用
> Dim ret As String = Regex.Replace("これとこれとこれとこれ", "これ", Function(sz) If(Interlocked.Add(n, 1) = 3, "あれ", "これ"))
引用返信 編集キー/
■44675 / inTopicNo.8)  Re[3]: VBの置換について。ひとつだけ置換は・・・できない??
□投稿者/ 魔界の仮面弁士 (1425回)-(2009/12/15(Tue) 17:16:56)
No44672 (やまり さん) に返信
> MSDNも眺めたのですが、Count:= でなんばんめ、というのが取れるのを読み取れませんでした・・・
「Replace(Src, "これ", "あれ", Count:=1)」の代わりに、
「Replace(Src, "これ", "あれ", , 1)」や
「Replace(Src, "これ", "あれ", 1, 1)」と書く事もできます。

それと先ほど
>> 汎用的にするなら、gtk2k さんの方法かな。
と書きましたが、下記のようにする必要がありそうです。

Dim ms As MatchCollection = Regex.Matches(strSrc, Regex.Escape(strMatch))
Dim strDst As String
If ms.Count = 0 Then
  strDst = strSrc
Else
  Dim idx As Integer = rnd.Next(ms.Count)
  strDst = strSrc.Substring(0, ms(idx).Index) & strReplace & strSrc.Substring(ms(idx).Index + strMatch.Length)
End If

Regex.Escape は、文字列に『(』などが含まれていた場合への備え、
If 判定は、一回もヒットしなかった場合に対応したものです。


>> Start:=x で、検索開始位置を調整することもできます。
> そんなこともできるんですね。これも使えそうですね。
Start 引数は、(検索回数ではなく)文字位置を表す引数なので、今回の用途では
ここに指定すべき数値を調べるためのコードが、別途必要になりますけれどね。


>> Function(sz) If(Interlocked.Add(n, 1) = 3
> これがちょっとどういう意味かわからないので、
VB のラムダ式では代入文を記述できないので、「n += 1」に相当するコードを、
Interlocked.Add メソッドで代用しています。


ラムダ式だと分かりにくいようであれば、先の Regex.Replace の部分を、
 matchedCount = 0
 ret = Regex.Replace("これとこれとこれとこれ", "これ", AddressOf Matched)
という記述に読み替えてみてください。

これは、
  文字列中に "これ" が見つかるたびに、Matched メソッドが呼び出され、
  その箇所が Matched メソッドの戻り値によって置換される
という処理を表しています。

ここでいう matchedCount や Matched は、たとえば下記のように実装されます。

 Module Foo
  Public matchedCount As Integer = 0
  Public Function Matched(ByVal m As Match) As String
   matchedCount += 1
   If matchedCount = 3 Then
    Return "あれ"
   Else
    Return "これ"
   End If
  End Function
 End Module


そして上記をラムダ式を使って短く記述したものが、先の
 n = 0
 ret = Regex.Replace("これとこれとこれとこれ", "これ", Function(x) If(Interlocked.Add(n, 1) = 3, "あれ", "これ"))
というわけです。

引用返信 編集キー/
■44681 / inTopicNo.9)  Re[1]: VBの置換について。ひとつだけ置換は・・・できない??
□投稿者/ 魔界の仮面弁士 (1426回)-(2009/12/15(Tue) 19:35:54)
No44652 (やまり さん) に返信
> 文字列の置換なのですが、ちょっと思いついたことがあって、

Replace 系のメソッドを使わずに実装してみました。

-----------
Dim src As String = "これとこれとこれとこれ"
Dim before As String = "これ"
Dim after As String = "あれ"

'Split 関数を使い、「これ」で分断して配列にする
Dim X As New List(Of String)(Split(src, before))

If X.Count > 2 Then
    '何番目を置き換えるかをランダムに決定
    Dim R As New Random()
    Dim I As Integer = R.Next(X.Count - 1)

    'その場所を「あれ」で繋げる
    X(I) &= after & X(I + 1)

    '繋いだ場所は取り除く
    X.RemoveAt(I + 1)
End If

'置き換えなかった場所をすべて「これ」で繋ぎ直して、文字列に戻す
Dim dst As String = Join(X.ToArray(), before)

引用返信 編集キー/


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

このトピックに書きこむ

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

管理者用

- Child Tree -