拥有String.Replace only hit的方法;全词”;

本文关键字:方法 全词 hit String Replace only 拥有 | 更新日期: 2023-09-27 17:57:56

我需要一种方法来实现这一点:

"test, and test but not testing.  But yes to test".Replace("test", "text")

返回这个:

"text, and text but not testing.  But yes to text"

基本上,我想替换整个单词,但不是部分匹配。

注意:我将不得不使用VB(SSRS 2008代码),但C#是我的普通语言,所以两者中的响应都很好。

拥有String.Replace only hit的方法;全词”;

正则表达式是最简单的方法:

string input = "test, and test but not testing.  But yes to test";
string pattern = @"'btest'b";
string replace = "text";
string result = Regex.Replace(input, pattern, replace);
Console.WriteLine(result);

模式的重要部分是'b元字符,它在单词边界上匹配。如果需要区分大小写,请使用RegexOptions.IgnoreCase:

Regex.Replace(input, pattern, replace, RegexOptions.IgnoreCase);

我创建了一个函数(请参阅此处的博客文章),该函数封装了Ahmad Mageed 建议的regex表达式

/// <summary>
/// Uses regex ''b' as suggested in https://stackoverflow.com/questions/6143642/way-to-have-string-replace-only-hit-whole-words
/// </summary>
/// <param name="original"></param>
/// <param name="wordToFind"></param>
/// <param name="replacement"></param>
/// <param name="regexOptions"></param>
/// <returns></returns>
static public string ReplaceWholeWord(this string original, string wordToFind, string replacement, RegexOptions regexOptions = RegexOptions.None)
{
    string pattern = String.Format(@"'b{0}'b", wordToFind);
    string ret=Regex.Replace(original, pattern, replacement, regexOptions);
    return ret;
}

正如Sga所评论的,regex解决方案并不完美。我想对表演也不友好。

以下是我的贡献:

public static class StringExtendsionsMethods
{
    public static String ReplaceWholeWord ( this String s, String word, String bywhat )
    {
        char firstLetter = word[0];
        StringBuilder sb = new StringBuilder();
        bool previousWasLetterOrDigit = false;
        int i = 0;
        while ( i < s.Length - word.Length + 1 )
        {
            bool wordFound = false;
            char c = s[i];
            if ( c == firstLetter )
                if ( ! previousWasLetterOrDigit )
                    if ( s.Substring ( i, word.Length ).Equals ( word ) )
                    {
                        wordFound = true;
                        bool wholeWordFound = true;
                        if ( s.Length > i + word.Length )
                        {
                            if ( Char.IsLetterOrDigit ( s[i+word.Length] ) )
                                wholeWordFound = false;
                        }
                        if ( wholeWordFound )
                            sb.Append ( bywhat );
                        else
                            sb.Append ( word );
                        i += word.Length;
                    }
            if ( ! wordFound )
            {
                previousWasLetterOrDigit = Char.IsLetterOrDigit ( c );
                sb.Append ( c );
                i++;
            }
        }
        if ( s.Length - i > 0 )
            sb.Append ( s.Substring ( i ) );
        return sb.ToString ();
    }
}

带有测试用例:

String a = "alpha is alpha";
Console.WriteLine ( a.ReplaceWholeWord ( "alpha", "alphonse" ) );
Console.WriteLine ( a.ReplaceWholeWord ( "alpha", "alf" ) );
a = "alphaisomega";
Console.WriteLine ( a.ReplaceWholeWord ( "alpha", "xxx" ) );
a = "aalpha is alphaa";
Console.WriteLine ( a.ReplaceWholeWord ( "alpha", "xxx" ) );
a = "alpha1/alpha2/alpha3";
Console.WriteLine ( a.ReplaceWholeWord ( "alpha", "xxx" ) );
a = "alpha/alpha/alpha";
Console.WriteLine ( a.ReplaceWholeWord ( "alpha", "alphonse" ) );

我只想添加一个关于这个特定正则表达式模式的注释(在接受的答案和ReplaceWholeWord函数中都使用)。如果你试图替换的不是一个单词,它就不起作用。

这里有一个测试用例:

using System;
using System.Text.RegularExpressions;
public class Test
{
    public static void Main()
    {
        string input = "doin' some replacement";
        string pattern = @"'bdoin''b";
        string replace = "doing";
        string result = Regex.Replace(input, pattern, replace);
        Console.WriteLine(result);
    }
}

(准备尝试代码:http://ideone.com/2Nt0A)

这一点必须考虑在内,尤其是当你正在进行批量翻译时(就像我在i18n的一些工作中所做的那样)。

如果您想定义单词的组成字符,即"_"answers"@"

你可以使用我的(vb.net)函数:

 Function Replace_Whole_Word(Input As String, Find As String, Replace As String)
      Dim Word_Chars As String = "ABCDEFGHIJKLMNOPQRSTUVWYXZabcdefghijklmnopqrstuvwyxz0123456789_@"
      Dim Word_Index As Integer = 0
      Do Until False
         Word_Index = Input.IndexOf(Find, Word_Index)
         If Word_Index < 0 Then Exit Do
         If Word_Index = 0 OrElse Word_Chars.Contains(Input(Word_Index - 1)) = False Then
            If Word_Index + Len(Find) = Input.Length OrElse Word_Chars.Contains(Input(Word_Index + Len(Find))) = False Then
               Input = Mid(Input, 1, Word_Index) & Replace & Mid(Input, Word_Index + Len(Find) + 1)
            End If
         End If
         Word_Index = Word_Index + 1
      Loop
      Return Input
   End Function

测试

Replace_Whole_Word("We need to replace words tonight. Not to_day and not too well to", "to", "xxx")

结果

"We need xxx replace words tonight. Not to_day and not too well xxx"

我不喜欢Regex,因为它很慢。我的功能更快。

public static string ReplaceWholeWord(this string text, string word, string bywhat)
{
    static bool IsWordChar(char c) => char.IsLetterOrDigit(c) || c == '_';
    StringBuilder sb = null;
    int p = 0, j = 0;
    while (j < text.Length && (j = text.IndexOf(word, j, StringComparison.Ordinal)) >= 0)
        if ((j == 0 || !IsWordChar(text[j - 1])) &&
            (j + word.Length == text.Length || !IsWordChar(text[j + word.Length])))
        {
            sb ??= new StringBuilder();
            sb.Append(text, p, j - p);
            sb.Append(bywhat);
            j += word.Length;
            p = j;
        }
        else j++;
    if (sb == null) return text;
    sb.Append(text, p, text.Length - p);
    return sb.ToString();
}

如果您对感兴趣,此方法也会忽略此情况

public static string Replace(this string s, string word, string by, StringComparison stringComparison, bool WholeWord)
{
    s = s + " ";
    int wordSt;
    StringBuilder sb = new StringBuilder();
    while (s.IndexOf(word, stringComparison) > -1)
    {
        wordSt = s.IndexOf(word, stringComparison);
        if (!WholeWord || ((wordSt == 0 || !Char.IsLetterOrDigit(char.Parse(s.Substring(wordSt - 1, 1)))) && !Char.IsLetterOrDigit(char.Parse(s.Substring(wordSt + word.Length, 1)))))
        {
            sb.Append(s.Substring(0, wordSt) + by);
        }
        else
        {
            sb.Append(s.Substring(0, wordSt + word.Length));
        }
        s = s.Substring(wordSt + word.Length);
    }
    sb.Append(s);
    return sb.ToString().Substring(0, sb.Length - 1);
}

您可以使用字符串替换

string input = "test, and test but not testing.  But yes to test";
string result2 = input.Replace("test", "text");
Console.WriteLine(input);
Console.WriteLine(result2);
Console.ReadLine();