string sentence = "We know it contains 'camel' Word.";
// Camel can be in different cases:
string s1 = "CAMEL";
string s2 = "CaMEL";
string s3 = "CAMeL";
// ...
string s4 = "Camel";
// ...
string s5 = "camel";
string.Replace
は左側の文字列でignoreCase
をサポートしていませんが、文中の 'camel'を 'horse'に置き換える方法は?
正規表現を使用します。
var regex = new Regex( "camel", RegexOptions.IgnoreCase );
var newSentence = regex.Replace( sentence, "horse" );
もちろん、これはラクダを含む単語にも一致しますが、それが必要かどうかは明確ではありません。
完全一致が必要な場合は、カスタムMatchEvaluatorを使用できます。
public static class Evaluators
{
public static string Wrap( Match m, string original, string format )
{
// doesn't match the entire string, otherwise it is a match
if (m.Length != original.Length)
{
// has a preceding letter or digit (i.e., not a real match).
if (m.Index != 0 && char.IsLetterOrDigit( original[m.Index - 1] ))
{
return m.Value;
}
// has a trailing letter or digit (i.e., not a real match).
if (m.Index + m.Length != original.Length && char.IsLetterOrDigit( original[m.Index + m.Length] ))
{
return m.Value;
}
}
// it is a match, apply the format
return string.Format( format, m.Value );
}
}
前の例で使用して、次のように一致をスパンにラップします。
var regex = new Regex( highlightedWord, RegexOptions.IgnoreCase );
foreach (var sentence in sentences)
{
var evaluator = new MatchEvaluator( match => Evaluators.Wrap( match, sentence, "<span class='red'>{0}</span>" ) );
Console.WriteLine( regex.Replace( sentence, evaluator ) );
}
文字列の拡張メソッドを追加して、トリックを実行します。
使用法:
string yourString = "TEXTTOREPLACE";
yourString.Replace("texttoreplace", "Look, I Got Replaced!", StringComparison.OrdinalIgnoreCase);
コード:
using System;
using System.Collections.Generic;
using System.IO;
public static class Extensions
{
public static string Replace(this string source, string oldString, string newString, StringComparison comp)
{
int index = source.IndexOf(oldString, comp);
// Determine if we found a match
bool MatchFound = index >= 0;
if (MatchFound)
{
// Remove the old text
source = source.Remove(index, oldString.Length);
// Add the replacemenet text
source = source.Insert(index, newString);
}
// recurse for multiple instances of the name
if (source.IndexOf(oldString, comp) != -1)
{
source = Replace(source, oldString, newString, comp);
}
return source;
}
}
String.IndexOfを使用して、StringComparisonを取得する拡張メソッドを次に示します。
[Pure]
public static string Replace(this string source, string oldValue, string newValue, StringComparison comparisonType)
{
if (source.Length == 0 || oldValue.Length == 0)
return source;
var result = new System.Text.StringBuilder();
int startingPos = 0;
int nextMatch;
while ((nextMatch = source.IndexOf(oldValue, startingPos, comparisonType)) > -1)
{
result.Append(source, startingPos, nextMatch - startingPos);
result.Append(newValue);
startingPos = nextMatch + oldValue.Length;
}
result.Append(source, startingPos, source.Length - startingPos);
return result.ToString();
}
ところで、これもStringComparisonを使用する同様のContainsメソッドです。
[Pure]
public static bool Contains(this string source, string value, StringComparison comparisonType)
{
return source.IndexOf(value, comparisonType) >= 0;
}
いくつかのテスト:
[TestFixture]
public class ExternalTests
{
private static string[] TestReplace_args =
{
"ab/B/c/ac",
"HELLO World/Hello/Goodbye/Goodbye World",
"Hello World/world/there!/Hello there!",
"hello WoRlD/world/there!/hello there!",
"///",
"ab///ab",
"/ab/cd/",
"a|b|c|d|e|f/|//abcdef",
"a|b|c|d|e|f|/|/:/a:b:c:d:e:f:",
};
[Test, TestCaseSource("TestReplace_args")]
public void TestReplace(string teststring)
{
var split = teststring.Split("/");
var source = split[0];
var oldValue = split[1];
var newValue = split[2];
var result = split[3];
Assert.That(source.Replace(oldValue, newValue, StringComparison.OrdinalIgnoreCase), Is.EqualTo(result));
}
}
Tom Beech's を sntbob's の再帰性と組み合わせた私の拡張メソッドと、 ksun が指摘したバグをよりきれいに修正します。
コード:
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
使用法:
string source = "banana";
Console.WriteLine(source.Replace("AN", "banana", StringComparison.OrdinalIgnoreCase));
結果:
バナナバナナ
そして、再帰的な性質をオプションにしたい場合:
コード:
public static string Replace(this string source, string oldString,
string newString, StringComparison comparison,
bool recursive = true)
{
int index = source.IndexOf(oldString, comparison);
while (index > -1)
{
source = source.Remove(index, oldString.Length);
source = source.Insert(index, newString);
if (!recursive)
{
return source;
}
index = source.IndexOf(oldString, index + newString.Length, comparison);
}
return source;
}
使用法:
string source = "banana";
Console.WriteLine(source.Replace("AN", "banana", StringComparison.OrdinalIgnoreCase, false));
結果:
バナナ
StringComparison
が便利なため、OrdinalIgnoreCase
を利用します
_ string sentence = "We know it contains 'camel' Word.";
string wordToFind = "camel";
string replacementWord = "horse";
int index = sentence.IndexOf(wordToFind , StringComparison.OrdinalIgnoreCase)
// Did we match the Word regardless of case
bool match = index >= 0;
// perform the replace on the matched Word
if(match) {
sentence = sentence.Remove(index, wordToFind.Length)
sentence = sentence.Insert(index, replacementWord)
}
_
C#文字列クラスにJavaのようなignoreCase()
メソッドがあれば、いいでしょう。
String.IndexOfを使用することもできます
http://msdn.Microsoft.com/en-us/library/system.string.indexof.aspx
RegExpressionsを使用するよりも、この方法でパフォーマンスが若干向上する場合があります(直感的で簡単に台無しになることはありませんが、この単純な.Net関数呼び出しは実際の乱雑なRegExを抽象化し、エラー)が、それはおそらくあなたにとって心配ではありません。最近のコンピュータは本当に速いですよね? :) StringComparisonオブジェクトを取得するIndexOfのオーバーロードにより、オプションで大文字と小文字を無視できます。IndexOfは指定された位置から最初のオカレンスを返すため、複数のオカレンスを持つ文字列を処理するループをコーディングする必要があります。
public static string CustomReplace(string srcText, string toFind, string toReplace, bool matchCase, bool replace0nce)
{
StringComparison sc = StringComparison.OrdinalIgnoreCase;
if (matchCase)
sc = StringComparison.Ordinal;
int pos;
while ((pos = srcText.IndexOf(toFind, sc)) > -1)
{
srcText = srcText.Remove(pos, toFind.Length);
srcText = srcText.Insert(pos, toReplace);
if (replace0nce)
break;
}
return srcText;
}
他の回答のいくつかほど効率的ではないかもしれませんが、sntbobによって作成されたCustomReplace関数が好きです。
しかし、そこには欠陥があります。テキスト置換が再帰的である場合、無限ループが発生します。たとえば、CustomReplace( "I eat bananas!"、 "an"、 "banana"、false、false)は無限ループを引き起こし、文字列は大きくなり続けます。たとえば、4回目の反復後、文字列は「I bbbbbananaanaanaanaanaanasを食べる!」になります。
「バナナ」内の「an」の2つのインスタンスのみを置き換えたい場合は、別のアプローチをとる必要があります。このケースを説明するためにsntbobのコードを修正しました。私はそれがはるかに複雑であることを認めますが、再帰的な置換を処理します。
public static string CustomReplace(string srcText, string toFind, string toReplace, bool matchCase, bool replaceOnce)
{
StringComparison sc = StringComparison.OrdinalIgnoreCase;
if (matchCase)
sc = StringComparison.Ordinal;
int pos;
int previousProcessedLength = 0;
string alreadyProcessedTxt = "";
string remainingToProcessTxt = srcText;
while ((pos = remainingToProcessTxt.IndexOf(toFind, sc)) > -1)
{
previousProcessedLength = alreadyProcessedTxt.Length;
//Append processed text up until the end of the found string and perform replacement
alreadyProcessedTxt += remainingToProcessTxt.Substring(0, pos + toFind.Length);
alreadyProcessedTxt = alreadyProcessedTxt.Remove(previousProcessedLength + pos, toFind.Length);
alreadyProcessedTxt = alreadyProcessedTxt.Insert(previousProcessedLength + pos, toReplace);
//Remove processed text from remaining
remainingToProcessTxt = remainingToProcessTxt.Substring(pos + toFind.Length);
if (replaceOnce)
break;
}
return alreadyProcessedTxt + remainingToProcessTxt;
}
なぜMicrosoft.VisualBasic名前空間をインポートしてVB Strings.Replaceメソッドを使用しないのですか?
https://msdn.Microsoft.com/en-us/library/Microsoft.visualbasic.strings.replace(v = vs.110).aspx
例えば
var newString = Strings.Replace(SourceString, FindTextValue, ReplacementTextValue, 1, -1, Constants.vbTextCompare);
vbTextCompareは、大文字と小文字を区別しない置換を強制します。仕事完了。
OK.
拡張メソッドとしてStringComparisonを使用するもう1つの代替方法を次に示します。 StringBuilderオブジェクト。 StringBuilderを使用すると、文字列を使用するよりもメモリを使用するほうが効率的である可能性があることを示す記事をいくつか読みました。必要な場合は、これを文字列で動作するように簡単に変更できます。
/// <summary>
/// Extension method to find/replace replaces text in a StringBuilder object
/// </summary>
/// <param name="original">Source StringBuilder object</param>
/// <param name="oldString">String to search for</param>
/// <param name="newString">String to replace each occurrance of oldString</param>
/// <param name="stringComparison">String comparison to use</param>
/// <returns>Original Stringbuilder with replacements made</returns>
public static StringBuilder Replace(this StringBuilder original,
string oldString, string newString, StringComparison stringComparison)
{
//If anything is null, or oldString is blank, exit with original value
if ( newString == null || original == null || string.IsNullOrEmpty(oldString))
return original;
//Convert to a string and get starting position using
//IndexOf which allows us to use StringComparison.
int pos = original.ToString().IndexOf(oldString, 0, stringComparison);
//Loop through until we find and replace all matches
while ( pos >= 0 )
{
//Remove the old string and insert the new one.
original.Remove(pos, oldString.Length).Insert(pos, newString);
//Get the next match starting 1 character after last replacement (to avoid a possible infinite loop)
pos = original.ToString().IndexOf(oldString, pos + newString.Length + 1, stringComparison);
}
return original;
}