C# Replace:一个熟悉而又陌生的替换

前言

Replace 的作用就是,通过指定内容的替换,返回一个新字符串。

返回值中,已将当前字符串中的指定 Unicode 字符或 String 的 所有匹配项,替换为指定的新的 Unicode 字符或 String。

一、String.Replace() 的几个重载

String.Replace() 总共有四个重载,分别是:(详见官网:String.Replace 方法

  Replace(Char, Char)、

  Replace(String, String)、

  Replace(String, String, StringComparison)、

  Replace(String, String, Boolean, CultureInfo)。

下面来逐个简单介绍下。

1、Replace(Char, Char)

// 作用: // 将实例中出现的所有指定 Unicode 字符都替换为另一个指定的 Unicode 字符。 // 语法: public string Replace (char oldChar, char newChar);

代码示例:

String str = "1 2 3 4 5 6 7 8 9"; Console.WriteLine($"Original string: {str}"); Console.WriteLine($"CSV string:      {str.Replace(' ', ',')}"); // 输出结果: // Original string: "1 2 3 4 5 6 7 8 9" // CSV string:      "1,2,3,4,5,6,7,8,9"

现在补充一下关于 Char 类型:

  char 类型关键字是 .NET System.Char 结构类型的别名,它表示 Unicode UTF-16 字符。

类型 范围 大小 .NET 类型 默认值
char U+0000 到 U+FFFF 16 位 System.Char 即 U+0000
// 给 Char 类型的变量赋值可以通过多重方式,如下: var chars = new[] {     'j',        //字符文本     'u006A',   //Unicode 转义序列,它是 u 后跟字符代码的十六进制表示形式(四个符号)     'x006A',   //十六进制转义序列,它是 x 后跟字符代码的十六进制表示形式     (char)106,  //将字符代码的值转换为相应的 char 值 }; Console.WriteLine(string.Join(" ", chars)); // 输出的值相同: j j j j

  char 类型可隐式转换为以下整型类型:ushort、int、uint、long 和 ulong。

  也可以隐式转换为内置浮点数值类型:float、double 和 decimal。

  可以显式转换为 sbyte、byte 和 short 整型类型。

2、String.Replace(String, String)

// 作用: // 实例中出现的所有指定字符串都替换为另一个指定的字符串 // 语法: public string Replace (char oldString, char newString);

示例:

// 目的:将错误的单词更正 string errString = "This docment uses 3 other docments to docment the docmentation"; Console.WriteLine($"The original string is:{Environment.NewLine}'{errString}'{Environment.NewLine}"); // 正确的拼写应该为 "document" string correctString = errString.Replace("docment", "document"); Console.WriteLine($"After correcting the string, the result is:{Environment.NewLine}'{correctString}'"); // 输出结果: // The original string is: // 'This docment uses 3 other docments to docment the docmentation' // // After correcting the string, the result is: // 'This document uses 3 other documents to document the documentation' //

 另一个示例:

// 可进行连续多次替换操作 String s = "aaa"; Console.WriteLine($"The initial string: '{s}'"); s = s.Replace("a", "b").Replace("b", "c").Replace("c", "d"); Console.WriteLine($"The final string: '{s}'"); // 如果 newString 为 null,则将 oldString 的匹配项全部删掉 s = s.Replace("dd", null); Console.WriteLine($"The new string: '{s}'");  // 输出结果: //The initial string: 'aaa' //The final string: 'ddd' //The new string: 'd'

 3、Replace(String, String, StringComparison)

相较于上一个重载,新增了一个入参枚举类型 StringComparison(详见官网:StringComparison 枚举)。作用是:指定供 Compare(String, String) 和 Equals(Object) 方法的特定重载,使用的区域性、大小写和排序规则。

相关源代码如下,可以看出,不同的 StringComparison 参数值对应的操作不同,最主要的区别就是是否添加参数 CultureInfo。

public string Replace(string oldValue, string? newValue, StringComparison comparisonType) { 	switch (comparisonType) 	{ 		case StringComparison.CurrentCulture: 		case StringComparison.CurrentCultureIgnoreCase: 			return ReplaceCore(oldValue, newValue, CultureInfo.CurrentCulture.CompareInfo,                                 GetCaseCompareOfComparisonCulture(comparisonType)); 		case StringComparison.InvariantCulture: 		case StringComparison.InvariantCultureIgnoreCase: 			return ReplaceCore(oldValue, newValue, CompareInfo.Invariant,                                 GetCaseCompareOfComparisonCulture(comparisonType)); 		case StringComparison.Ordinal: 			return Replace(oldValue, newValue); 		case StringComparison.OrdinalIgnoreCase: 			return ReplaceCore(oldValue, newValue, CompareInfo.Invariant, CompareOptions.OrdinalIgnoreCase); 		default: 			throw new ArgumentException(SR.NotSupported_StringComparison, "comparisonType"); 	} }

关于不同区域的不同 CultureInfo 实例,程序运行结果的区别,见下面的示例:

查看代码
// 以下示例为三种语言("zh-CN", "th-TH", "tr-TR")不同枚举值的测试代码和输出结果: String[] cultureNames = { "zh-CN", "th-TH", "tr-TR" }; // 中国 泰国 土耳其 String[] strings1 = { "a", "i", "case", }; String[] strings2 = { "a-", "u0130", "Case" }; StringComparison[] comparisons = (StringComparison[])Enum.GetValues(typeof(StringComparison)); foreach (var cultureName in cultureNames) {     Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName);     Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.Name);     for (int ctr = 0; ctr <= strings1.GetUpperBound(0); ctr++)     {         foreach (var comparison in comparisons)             Console.WriteLine("   {0} = {1} ({2}): {3}", strings1[ctr], strings2[ctr], comparison,                               String.Equals(strings1[ctr], strings2[ctr], comparison));         Console.WriteLine();     }     Console.WriteLine(); }  // 输出结果: // Current Culture: zh-CN //    a = a- (CurrentCulture): False //-----注意------ //    a = a- (CurrentCultureIgnoreCase): False //-----注意------ //    a = a- (InvariantCulture): False //    a = a- (InvariantCultureIgnoreCase): False //    a = a- (Ordinal): False //    a = a- (OrdinalIgnoreCase): False //  //    i = İ (CurrentCulture): False //    i = İ (CurrentCultureIgnoreCase): False //-----注意------ //    i = İ (InvariantCulture): False //    i = İ (InvariantCultureIgnoreCase): False //    i = İ (Ordinal): False //    i = İ (OrdinalIgnoreCase): False //  //    case = Case (CurrentCulture): False //    case = Case (CurrentCultureIgnoreCase): True //    case = Case (InvariantCulture): False //    case = Case (InvariantCultureIgnoreCase): True //    case = Case (Ordinal): False //    case = Case (OrdinalIgnoreCase): True //  //  // Current Culture: th-TH //    a = a- (CurrentCulture): True //-----注意------ //    a = a- (CurrentCultureIgnoreCase): True //-----注意------ //    a = a- (InvariantCulture): False //    a = a- (InvariantCultureIgnoreCase): False //    a = a- (Ordinal): False //    a = a- (OrdinalIgnoreCase): False //  //    i = İ (CurrentCulture): False //    i = İ (CurrentCultureIgnoreCase): False //    i = İ (InvariantCulture): False //    i = İ (InvariantCultureIgnoreCase): False //    i = İ (Ordinal): False //    i = İ (OrdinalIgnoreCase): False //  //    case = Case (CurrentCulture): False //    case = Case (CurrentCultureIgnoreCase): True //    case = Case (InvariantCulture): False //    case = Case (InvariantCultureIgnoreCase): True //    case = Case (Ordinal): False //    case = Case (OrdinalIgnoreCase): True //  //  // Current Culture: tr-TR //    a = a- (CurrentCulture): False //    a = a- (CurrentCultureIgnoreCase): False //    a = a- (InvariantCulture): False //    a = a- (InvariantCultureIgnoreCase): False //    a = a- (Ordinal): False //    a = a- (OrdinalIgnoreCase): False //  //    i = İ (CurrentCulture): False //    i = İ (CurrentCultureIgnoreCase): True //-----注意------ //    i = İ (InvariantCulture): False //    i = İ (InvariantCultureIgnoreCase): False //    i = İ (Ordinal): False //    i = İ (OrdinalIgnoreCase): False //  //    case = Case (CurrentCulture): False //    case = Case (CurrentCultureIgnoreCase): True //    case = Case (InvariantCulture): False //    case = Case (InvariantCultureIgnoreCase): True //    case = Case (Ordinal): False //    case = Case (OrdinalIgnoreCase): True

4、Replace(String, String, Boolean, CultureInfo)

此重载主要介绍下后两个入参。

Boolean:布尔类型入参,默认 false。true:忽略大小写;false:区分大小写。

CultureInfo:指定代码的区域性,允许为 null,但必须站位。为空时当前区域(CultureInfo.CurrentCulture.CompareInfo)。

注:关于 CultureInfo 的详细测试示例,详见上一部分中的折叠代码。

以下是当前重载的部分源码:

查看代码
 public string Replace(string oldValue, string? newValue, bool ignoreCase, CultureInfo? culture) { 	return ReplaceCore(oldValue, newValue, culture?.CompareInfo, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None); } private string ReplaceCore(string oldValue, string newValue, CompareInfo ci, CompareOptions options) { 	if ((object)oldValue == null) 	{ 		throw new ArgumentNullException("oldValue"); 	} 	if (oldValue.Length == 0) 	{ 		throw new ArgumentException(SR.Argument_StringZeroLength, "oldValue"); 	} 	return ReplaceCore(this, oldValue.AsSpan(), newValue.AsSpan(), ci ?? CultureInfo.CurrentCulture.CompareInfo, options) ?? this; } private static string ReplaceCore(ReadOnlySpan<char> searchSpace, ReadOnlySpan<char> oldValue, ReadOnlySpan<char> newValue, CompareInfo compareInfo, CompareOptions options) { 	Span<char> initialBuffer = stackalloc char[256]; 	ValueStringBuilder valueStringBuilder = new ValueStringBuilder(initialBuffer); 	valueStringBuilder.EnsureCapacity(searchSpace.Length); 	bool flag = false; 	while (true) 	{ 		int matchLength; 		int num = compareInfo.IndexOf(searchSpace, oldValue, options, out matchLength); 		if (num < 0 || matchLength == 0) 		{ 			break; 		} 		valueStringBuilder.Append(searchSpace.Slice(0, num)); 		valueStringBuilder.Append(newValue); 		searchSpace = searchSpace.Slice(num + matchLength); 		flag = true; 	} 	if (!flag) 	{ 		valueStringBuilder.Dispose(); 		return null; 	} 	valueStringBuilder.Append(searchSpace); 	return valueStringBuilder.ToString(); }

二、Regex.Replace() 的几个常用重载

1、Replace(String, String)

在指定的输入字符串(input)内,使用指定的替换字符串(replacement),替换与某个正则表达式模式(需要在实例化 Regex 对象时,将正则表达式传入)匹配的所有的字符串。

// 语法 public string Replace (string input, string replacement);

下面是一个简单的示例:

// 目的是将多余的空格去掉 string input = "This is   text with   far  too   much   white space."; string pattern = "\s+"; // s:匹配任何空白字符;+:匹配一次或多次 string replacement = " "; Regex rgx = new Regex(pattern); // 实例化时传入正则表达式 string result = rgx.Replace(input, replacement); Console.WriteLine("Original String: {0}", input); Console.WriteLine("Replacement String: {0}", result); // 输出结果: // Original String: This is   text with   far  too   much   white space. // Replacement String: This is text with far too much white space.

 2、Replace(String, String, String)

在指定的输入字符串内(input),使用指定的替换字符串(replacement)替换与指定正则表达式(pattern)匹配的所有字符串。

// 语法: public static string Replace (string input, string pattern, string replacement);
// 目的:将多余的空格去掉 string input = "This is   text with   far  too   much   white space."; string pattern = "\s+";  // 注:s  匹配任何空白字符,包括空格、制表符、换页符等 // 注:+   重复一次或多次 string replacement = " "; // 将连续出现的多个空格,替换为一个 string result = Regex.Replace(input, pattern, replacement); Console.WriteLine("Original String: {0}", input); Console.WriteLine("Replacement String: {0}", result); // 输出结果: //Original String: This is text with   far too   much white space. //Replacement String: This is text with far too much white space.

3、Replace(String, String, Int32, Int32)

在指定输入子字符串(input)内,使用指定替换字符串(replacement)替换与某个正则表达式模式匹配的字符串(其数目为指定的最大数目)。startat 是匹配开始的位置。

// 语法: public string Replace (string input, string replacement, int count, int startat);

 下面是一个示例:

// 目的:添加双倍行距 string input = "Instantiating a New Typen" +     "Generally, there are two ways that ann" +     "instance of a class or structure cann" +     "be instantiated. "; Console.WriteLine("原内容:"); Console.WriteLine(input); // .:匹配除‘n’之外的任何单个字符;*:匹配零次或多次 string pattern = "^.*$"; // ^.*$ 在这里就是匹配每一行中‘n’前边的字符串 string replacement = "n$&"; // 在匹配项前添加‘n’;$&:代表匹配内容 Regex rgx = new Regex(pattern, RegexOptions.Multiline); // Multiline:多行模式,不仅仅在整个字符串的开头和结尾匹配 string result = string.Empty; Match match = rgx.Match(input); // 判断能否匹配 if (match.Success)     result = rgx.Replace(input,                           replacement,                          -1, // >= 0 时,就是匹配具体次数,= -1 时就是不限制次数                          match.Index + match.Length + 1 // 作用就是跳过第一个匹配项(第一行不做处理)                          // 当第一次匹配时:Index=0,length=除了‘n’之外的长度,最后再 +1 就是第一行全部的内容                         ); Console.WriteLine("结果内容:"); Console.WriteLine(result); // 输出结果: // 原内容: // Instantiating a New Type // Generally, there are two ways that an // instance of a class or structure can // be instantiated. // 结果内容: // Instantiating a New Type //  // Generally, there are two ways that an //  // instance of a class or structure can //  // be instantiated.

4、Replace(String, String, MatchEvaluator, RegexOptions, TimeSpan)

在入参字符串(input)中,进行正则表达式(pattern)的匹配,匹配成功的,传递给 MatchEvaluator 委托(evaluator)处理完成后,替换原匹配值。

RegexOptions 为匹配操作配置项(关于 RegexOptions 详见官网:RegexOptions 枚举),TimeSpan 为超时时间间隔。

public static string Replace (string input, string pattern,                                System.Text.RegularExpressions.MatchEvaluator evaluator,                                System.Text.RegularExpressions.RegexOptions options,                                TimeSpan matchTimeout);

下面是一个示例:

// 目的:将输入的每个单词中的字母顺序随机打乱,再一起输出 static void Main(string[] args) {     string words = "letter alphabetical missing lack release " +         "penchant slack acryllic laundry cease";     string pattern = @"w+  # Matches all the characters in a word.";     MatchEvaluator evaluator = new MatchEvaluator(WordScrambler); // WordScrambler:回调函数     Console.WriteLine("Original words:");     Console.WriteLine(words);     Console.WriteLine();     try     {         Console.WriteLine("Scrambled words:");         Console.WriteLine(Regex.Replace(words, pattern, evaluator,                 RegexOptions.IgnorePatternWhitespace, TimeSpan.FromSeconds(2)));     }     catch (RegexMatchTimeoutException)     {         Console.WriteLine("Word Scramble operation timed out.");         Console.WriteLine("Returned words:");     } } /// <summary> /// 回调:对全部匹配项逐一进行操作 /// </summary> /// <param name="match"></param> /// <returns></returns> public static string WordScrambler(Match match) {     int arraySize = match.Value.Length;     double[] keys = new double[arraySize]; // 存放随机数     char[] letters = new char[arraySize]; // 存放字母     Random rnd = new Random();     for (int ctr = 0; ctr < match.Value.Length; ctr++)     {         keys[ctr] = rnd.NextDouble(); // 生成随机数,用于重新排序         letters[ctr] = match.Value[ctr]; // 将输入参单词数拆解为字母数组     }     Array.Sort(keys, letters, 0, arraySize, Comparer.Default); // 重新根据随机数大小排序     return new String(letters); } // 输出结果: // Original words: // letter alphabetical missing lack release penchant slack acryllic laundry cease //  // Scrambled words: // eltetr aeplbtaiaclh ignisms lkac elsaree nchetapn acksl lcyaricl udarnly casee

三、关于 Replace 的实际需求简单示例

1、全部替换匹配项

string input = "Instantiating Instantiating Instantiating Instantiating"; Console.WriteLine("----原内容----"); Console.WriteLine(input); string result = input.Replace("tiating","*******"); Console.WriteLine("----结果内容----"); Console.WriteLine(result); // ----原内容---- // Instantiating Instantiating Instantiating Instantiating // ----结果内容---- // Instan******* Instan******* Instan******* Instan*******

2、仅替换第一个匹配项

string input = "Instantiating Instantiating Instantiating Instantiating"; Console.WriteLine("----原内容----"); Console.WriteLine(input); Regex regex = new Regex("tiating"); string result = regex.Replace(input, "*******",1); Console.WriteLine("----结果内容----"); Console.WriteLine(result); // ----原内容---- // Instantiating Instantiating Instantiating Instantiating // ----结果内容---- // Instan******* Instantiating Instantiating Instantiating

3、仅替换最后一个匹配项

string input = "Instantiating Instantiating Instantiating Instantiating"; Console.WriteLine("----原内容----"); Console.WriteLine(input); Match match = Regex.Match(input, "tiating",RegexOptions.RightToLeft); string first = input.Substring(0, match.Index); string last = input.Length == first.Length + match.Length ? "" :  input.Substring(first.Length + match.Length,input.Length-(first.Length + match.Length)); string result = $"{first}*******{last}"; Console.WriteLine("----结果内容----"); Console.WriteLine(result); // 两次测试结果: // ----原内容---- // Instantiating Instantiating Instantiating Instantiating 345 // ----结果内容---- // Instantiating Instantiating Instantiating Instan******* 345 // ----原内容---- // Instantiating Instantiating Instantiating Instantiating // ----结果内容---- // Instantiating Instantiating Instantiating Instan*******

参考:String.Replace 方法

     Regex.Replace 方法

注:如有建议或疑问,欢迎留言。

发表评论

相关文章