C# 如何在不发生特定事件的情况下替换特定字符串

C# 如何在不发生特定事件的情况下替换特定字符串,c#,string,replace,pattern-matching,C#,String,Replace,Pattern Matching,此处的文本示例: text=“第44.7h3章v3nd3774” 我希望它像这样输出 outcome=“第44章竞技场” 如果我只是使用这样的方法: 字符串s=文本。替换(“4”,“a”)。替换(“3”,“e”)。替换(“6”,“g”)。替换(“1”,“I”)。替换(“0”,“o”)。替换(“5”,“s”)。替换(“7”,“t”) System.Console.WriteLine(“WriteText.txt的内容={0}”,s) 将输出为第aa章。仇杀,正确的部分也会改变,想知道是否会有一

此处的文本示例:

text=“第44.7h3章v3nd3774”

我希望它像这样输出

outcome=“第44章竞技场”


如果我只是使用这样的方法: 字符串s=文本。替换(“4”,“a”)。替换(“3”,“e”)。替换(“6”,“g”)。替换(“1”,“I”)。替换(“0”,“o”)。替换(“5”,“s”)。替换(“7”,“t”)

System.Console.WriteLine(“WriteText.txt的内容={0}”,s)



将输出为
第aa章。仇杀
,正确的部分也会改变,想知道是否会有一些简单的解决方案?

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

从您的示例中可以看出,只有当数字与字母直接相邻时,才需要将其更改为字母。如果这是唯一的规则,那么您可以这样做:

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"
公共静态字符串转换(字符串输入)
{
if(string.IsNullOrEmpty(input))返回输入;
var charMap=新字典
{
{'4','a'},{'3','e'},{'6','g'},{'1','i'},
{'0','o'},{'5','s'},{'7','t'}
};
var后缀=新列表
{
“st”、“nd”、“rd”、“th”
};
var result=新的StringBuilder();
对于(变量i=0;i0&&char.isleter(结果[i-1]))||
(i=0&&charMap.ContainsKey(结果[prevIndex]))
{
结果[prevIndex]=字符映射[result[prevIndex];
前置索引--;
}
}
其他的
{
结果.追加(输入[i]);
}
}
返回result.ToString();
}
//确定数字后面是否跟有“有效后缀”的Helper方法,
//用于防止在应保留数字时转换数字
//数量;例如“24th”,我们不想将“4”改为“a”。
公共静态bool IsValidSuffix(字符串输入,列出validsuffix)
{
if(input==null)返回validSuffix==null;
if(input==string.Empty)返回true;
if((validSuffixes?.Count).GetValueOrDefault()==0)返回false;
var match=validsuffix
.OrderByDescending(s=>s.Length)
.FirstOrDefault(input.StartsWith);
返回匹配!=null&&
(input.Length==match.Length||
!char.isleter(输入[match.Length]);
}
//输出:翻译(“第44章。7h3 v3nd3774”)=“第44章。世仇”

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

以下是代码建议: `

void Main()
{
var text=“第44.7h3章v3nd3774”;
var结果=移除(文本);
控制台写入线(结果);
}
布尔数字(字符c)
{
返回c>='0'&&c='a'&&c='a'&&c>='Z';
}
string RemoveLeet(字符串文本)
{
var sb=新的StringBuilder(文本);
某人
替换;替换;替换;替换;替换
替换;替换;替换;替换;替换;
变量结果=sb.ToString();
for(int i=0;i

`

此替换的逻辑是什么?您如何知道哪个部分是正确的部分?如果您可以表达用于确定应转换哪些数字的逻辑规则,那么是的,这应该不会太难。仅供参考,
char
类型已经有静态的
IsDigit
islater
方法可以使用。例如,您可以这样做:
if(char.IsDigit(text[i++])
It is leet convert!但并没有提供明显的规则,我认为文本被leet变化随机污染,需要重新解码,而原始文本是正常的段落。不确定是否需要更多信息?是的,此解决方案确实输出了最准确的输出,但有一个例外情况“在1815年2月24日”,输出为“在1815年2月2日”(而原始解决方案没有)
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;
}