如何在没有特定事件的情况下替换特定字符串

How to replace certain string without certain occurrence

例如此处的文本:

text = "Chapter 44. 7h3 v3nd3774"

我想要这样输出

outcome = "Chapter 44. The colosseum"


如果我只是使用这样的方法:

string s = text.Replace("4", "a").Replace("3", "e").Replace("6", "g").Replace("1", "I").Replace("0", "o").Replace("5", "s").Replace("7", "t");

System.Console.WriteLine("Contents of WriteText.txt = {0}", s);


会输出为Chapter aa. the vendetta,正确的部分也变了,不知道有没有简单的解决办法?

如果您可以表达用于确定哪些数字应该转换的逻辑规则,那么是的,那应该不会太难。

从您的示例来看,您似乎只想将数字更改为与字母直接相邻的字母。如果这是唯一的规则,那么您可以这样做:

public static string Translate(string input)
{
    if (string.IsNullOrEmpty(input)) return input;

    var charMap = new Dictionary<char, char>
    {
        {'4', 'a'}, {'3', 'e'}, {'6', 'g'}, {'1', 'i'},
        {'0', 'o'}, {'5', 's'}, {'7', 't'}
    };

    var suffixes = new List<string>
    {
        "st", "nd", "rd", "th"
    };

    var result = new StringBuilder();

    for (var i = 0; i < input.Length; i++)
    {
        // If the previous or next character is a letter and this character
        // is in the mapping dictionary, replace it with the mapped character
        if (((i > 0 && char.IsLetter(result[i - 1])) ||
                (i < input.Length - 1 && char.IsLetter(input[i + 1]))) &&
            charMap.ContainsKey(input[i]) && 
            (i == input.Length - 1 || !IsValidSuffix(input.Substring(i + 1), suffixes)))
        {
            result.Append(charMap[input[i]]);

            // Because we're changing characters from left to right and we just
            // changed this character to a letter, we need to walk backwards and 
            // check the previous characters since they may now need to change.
            // For example the 51 in '517u4710n' would not change without this check
            var prevIndex = i - 1;
            while (prevIndex >= 0 && charMap.ContainsKey(result[prevIndex]))
            {
                result[prevIndex] = charMap[result[prevIndex]];
                prevIndex--;
            }
        }
        else
        {
            result.Append(input[i]);
        }
    }

    return result.ToString();
}

// Helper method to determine if a number is followed by a "valid suffix", 
// which is used to prevent converting numbers when they should remain
// numbers; such as "24th", where we don't want to change the '4' to an 'a'.
public static bool IsValidSuffix(string input, List<string> validSuffixes)
{
    if (input == null) return validSuffixes == null;
    if (input == string.Empty) return true;
    if ((validSuffixes?.Count).GetValueOrDefault() == 0) return false;

    var match = validSuffixes
        .OrderByDescending(s => s.Length)
        .FirstOrDefault(input.StartsWith);

    return match != null &&
            (input.Length == match.Length ||
            !char.IsLetter(input[match.Length]));
}

// Output: Translate("Chapter 44. 7h3 v3nd3774") == "Chapter 44. the vendetta"

如果您的逻辑是将整数保留为 'correct' 部分,您可以尝试在应用替换逻辑后找到这些数字并将它们放回 'corrected' 句子中。 此外,当您多次更改字符串时,我建议使用 StringBuilder 来解决性能问题。

这里是一个代码建议: `

void Main()
{
    var text = "Chapter 44. 7h3 v3nd3774";
    var outcome = RemoveLeet(text);
    Console.WriteLine(outcome);
}

bool IsDigit(char c)
{
    return c >= '0' && c <= '9';
}

bool IsLetter(char c)
{
    return c >= 'a' && c <= 'z' || c >= 'A' && c >= 'Z';
}

string RemoveLeet(string text)
{
    var sb = new StringBuilder(text);
    sb
    .Replace("4", "a").Replace("3", "e").Replace("6", "g").Replace("1", "I")
    .Replace("0", "o").Replace("5", "s").Replace("7", "t");
    var outcome = sb.ToString();
    for (int i = 0; i < text.Length;)
    {
        if (IsDigit(text[i++]))
        {
            int numberLength = 1;
            for (;i < text.Length; i++)
            {
                if (!IsDigit(text[i]))
                    break;
                numberLength += 1;
            }
            var indexBeforeNumber = i - numberLength - 1;
            //check number did not start inside a word
            if (indexBeforeNumber < 0 || !IsLetter(text[indexBeforeNumber]))
            {
                //check number is not followed by a word
                if (i == text.Length || !IsLetter(text[i]))
                {
                    var number = text.Substring(i - numberLength, numberLength);
                    var outcomeBegin = indexBeforeNumber < 1 ? "" : outcome.Substring(0, indexBeforeNumber + 1);
                    var outcomeAfter = i == text.Length ? "" : outcome.Substring(i, text.Length - i);
                    outcome = $"{outcomeBegin}{number}{outcomeAfter}";
                }
            }
        }
    }
    return outcome;
}

`