0

C# Replace:一个熟悉而又陌生的替换 - 橙子家

 1 year ago
source link: https://www.cnblogs.com/czzj/p/ReplaceInfo.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client



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 \0 即 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 Type\n" +
    "Generally, there are two ways that an\n" +
    "instance of a class or structure can\n" +
    "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 方法

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK