DOBON.NET DOBON.NETプログラミング掲示板過去ログ

大文字小文字/全角半角の区別なしの文字列の置換

環境/言語:[VB.NET]
分類:[.NET]

こんにちは。はじめて投稿します。
.NET環境で、置換対象の文字列が大文字・小文字・全角・半角の区別なく置換したいと考えています。
具体的には、「パピプぺポ」(→"ピ"と"ぺ"は、半角カナ文字です)とか「パピプペポ」を「はひふへほ」に変換します(この例では大文字・小文字は関係ありませんが)。ただし、ひらがな(「ぱぴぷぺぽ」)は変換したくありません
.NET Tipsの『文字列を置換する』の中のコーディング例(StringReplace)は、変換対象が半角カナ文字がなければ問題ないのですが、半角カナ文字があった場合、変換対象の文字数(「パピプぺポ」(→"ピ"と"ぺ"は、半角カナ文字です)は、7文字になる)が検索する文字数(「パピプペポ」は5文字)なので、変換せずに一部の文字が残ってしまいます。
そこで、StringReplaceを少し改造してみました。

改造部分は、置換対象文字列を検索して、見つかったら、変換対象の文字列の文字数を調べるコードを追加しました。
下記は、改造したコードです。

''' <summary>
''' 指定した文字列内の指定した文字列を別の文字列に置換する。
''' </summary>
''' <param name="input">置換する文字列のある文字列。</param>
''' <param name="oldValue">検索文字列。</param>
''' <param name="newValue">置換文字列。</param>
''' <param name="count">置換する回数。負の数が指定されたときは、すべて置換する。</param>
''' <param name="compInfo">文字列の検索に使用するCompareInfo。</param>
''' <param name="compOptions">文字列の検索に使用するCompareOptions。</param>
''' <returns>置換された結果の文字列。</returns>
Public Shared Function StringReplace(ByVal input As String, ByVal oldValue As String,
ByVal newValue As String, ByVal count As Integer,
ByVal compInfo As System.Globalization.CompareInfo,
ByVal compOptions As System.Globalization.CompareOptions) As String

If (input Is Nothing OrElse input.Length = 0 _
OrElse oldValue Is Nothing _
OrElse oldValue.Length = 0 OrElse count = 0) Then

Return input
End If

If (compInfo Is Nothing) Then
compInfo = System.Globalization.CultureInfo.InvariantCulture.CompareInfo
compOptions = System.Globalization.CompareOptions.Ordinal
End If

Dim inputLen As Integer = input.Length
Dim oldValueLen As Integer = oldValue.Length
Dim buf As New System.Text.StringBuilder(inputLen)

Dim currentPoint As Integer = 0
Dim foundPoint As Integer = -1
Dim currentCount As Integer = 0
Dim workStr As String
Dim replaceTargetLen As Integer

Do
'文字列を検索する
foundPoint = compInfo.IndexOf(input, oldValue, currentPoint, compOptions)
If (foundPoint < 0) Then
buf.Append(input.Substring(currentPoint))
Exit Do
End If

' 追加したコード
'==============================================================================
' 見つかった文字列の文字数を調べる
For replaceTargetLen = 1 To input.Length - foundPoint - currentPoint
workStr = input.Substring(foundPoint, replaceTargetLen)
If (compInfo.Compare(workStr, oldValue, compOptions) = 0) Then
Exit For
End If
Next
'======================= ここまで
'見つかった文字列を新しい文字列に換える
buf.Append(input.Substring(currentPoint, foundPoint - currentPoint))
buf.Append(newValue)

'次の検索開始位置を取得
' 次の検索開始位置は、変換対象の文字列の文字数分移動
currentPoint = foundPoint + replaceTargetLen

'指定回数置換したか調べる
currentCount += 1
If currentCount = count Then
buf.Append(input.Substring(currentPoint))
Exit Do
End If
Loop While currentPoint < inputLen

Return buf.ToString()
End Function


こんな方法しか思いつかなかったのですが、他によい方法があるでしょうか。
■No29897に返信(ackey-tさんの記事)

こんにちは。

No29896 のご投稿は、このご投稿とほぼ同じ内容でしたので(半角カナ文字を全角に直して再び投稿していただいたのでしょうか)、削除させて頂きました。

> こんな方法しか思いつかなかったのですが、他によい方法があるでしょうか。

大文字小文字を区別しないで、回数を指定して置換する
http://dobon.net/vb/dotnet/string/replace.html#section6

のコードは、確かにご指摘の点を考慮していませんでした。申し訳ありません。

私もこれといった方法を思い付きません。ただ、 No29897 のコードはSubstringで文字列を切り出していますが、そうせずにCompareInfo.Compareメソッドで比較する位置と長さを指定した方が良いのではないでしょうか。
■No29902に返信(管理人さんの記事)
> No29896 のご投稿は、このご投稿とほぼ同じ内容でしたので(半角カナ文字を全角に直して再び投稿していただいたのでしょうか)、削除させて頂きました。
すみません、半角文字をそのまま使った投稿を修正しようと思って、2回投稿してしまいました。
削除しようとしたのですが、「パスワードが違います」で削除できず...
お手数をおかけしました
>
>>こんな方法しか思いつかなかったのですが、他によい方法があるでしょうか。
>
> 大文字小文字を区別しないで、回数を指定して置換する
> http://dobon.net/vb/dotnet/string/replace.html#section6
>
> のコードは、確かにご指摘の点を考慮していませんでした。申し訳ありません。
いえいえ、Strings.Replaceメソッドが、検索と同じオプションで動作してくれればよいのに。

> 私もこれといった方法を思い付きません。ただ、 No29897 のコードはSubstringで文字列を切り出していますが、そうせずにCompareInfo.Compareメソッドで比較する位置と長さを指定した方が良いのではないでしょうか。

そうですね。わざわざSubstringで文字列を取りだす必要はないですね。
ご指摘、ありがとうございます。

DOBON.NET | プログラミング道 | プログラミング掲示板