Заменить текст, сохранив регистр в C#

у меня есть набор предложений, которые мне нужно использовать для замены, например:

abc => cde
ab df => de
...

и у меня есть текст, где сделать изменения. Однако у меня нет способа узнать заранее случай указанного текста. Так, например, если у меня есть:

A bgt abc hyi. Abc Ab df h

Я должен заменить и получить:

A bgt cde nyi. Cde De h

или как можно ближе к этому, т. е. сохранить case

EDIT: поскольку я вижу много путаницы об этом, я попытаюсь прояснить бит:

Я спрашиваю о способе сохранить шапки после замены, и я не думаю, что прошел хорошо (не очень хорошо объяснил, что влечет за собой thaat), поэтому я приведу более реалистичный пример, используя реальные слова.

думайте об этом как о госсари, заменяя выражения их синонимами, так сказать, так что если я карта:

didn't achieve success => failled miserably

затем я получаю как вход setence:

As he didn't achieve success, he was fired

Я бы

As he failled miserably, he was fired

но если бы не было заглавной буквы, так бы failled, если бы достижение или успех были капитализированы, так было бы несчастливо, если бы у кого-то было более 1 буквы с капитализацией, так что это коллега

мои основные возможности (те, которые я действительно хочу принять в cosideration)

  • только первая буква первого слова с заглавной буквы
  • только первая буква каждого слова с заглавной буквы
  • все буквы капитализируются

если я могу справиться с теми тремя, Что бы acceaptable уже я угадайте - это более легкие - конечно, более глубокое решение было бы лучше, если бы availlable

какие идеи?

5 ответов


Не уверен, насколько хорошо это будет работать, но это то, что я придумал:

        string input = "A bgt abc hyi. Abc Ab df h";
        Dictionary<string, string> map = new Dictionary<string, string>();
        map.Add("abc", "cde");
        map.Add("ab df", "de");

        string temp = input;
        foreach (var entry in map)
        {
            string key = entry.Key;
            string value = entry.Value;
            temp = Regex.Replace(temp, key, match =>
            {
                bool isUpper = char.IsUpper(match.Value[0]);

                char[] result = value.ToCharArray();
                result[0] = isUpper
                    ? char.ToUpper(result[0])
                    : char.ToLower(result[0]);
                return new string(result);
            }, RegexOptions.IgnoreCase);
        }
        label1.Text = temp; // output is A bgt cde hyi. Cde De h

редактировать После прочтения измененного вопроса, вот мой измененный код (оказывается, это аналогичные шаги для кода @Sephallia.. и похожие имена переменных lol)

код теперь немного сложнее.. но я думаю, что все в порядке

        string input = 
        @"As he didn't achieve success, he was fired.
        As he DIDN'T ACHIEVE SUCCESS, he was fired.
        As he Didn't Achieve Success, he was fired.
        As he Didn't achieve success, he was fired.";
        Dictionary<string, string> map = new Dictionary<string, string>();
        map.Add("didn't achieve success", "failed miserably");


        string temp = input;
        foreach (var entry in map)
        {
            string key = entry.Key;
            string value = entry.Value;
            temp = Regex.Replace(temp, key, match =>
            {
                bool isFirstUpper, isEachUpper, isAllUpper;

                string sentence = match.Value;
                char[] sentenceArray = sentence.ToCharArray();

                string[] words = sentence.Split(' ');

                isFirstUpper = char.IsUpper(sentenceArray[0]);

                isEachUpper = words.All(w => char.IsUpper(w[0]) || !char.IsLetter(w[0]));

                isAllUpper = sentenceArray.All(c => char.IsUpper(c) || !char.IsLetter(c));

                if (isAllUpper)
                    return value.ToUpper();

                if (isEachUpper)
                {
                    // capitalize first of each word... use regex again :P
                    string capitalized = Regex.Replace(value, @"\b\w", charMatch => charMatch.Value.ToUpper());
                    return capitalized;
                }


                char[] result = value.ToCharArray();
                result[0] = isFirstUpper
                    ? char.ToUpper(result[0])
                    : char.ToLower(result[0]);
                return new string(result);
            }, RegexOptions.IgnoreCase);
        }
        textBox1.Text = temp; 
        /* output is :
        As he failed miserably, he was fired.
        As he FAILED MISERABLY, he was fired.
        As he Failed Miserably, he was fired.
        As he Failed miserably, he was fired.
        */

можно использовать строку.Метод indexOf С StringComparison.CurrentCultureIgnoreCase указано, чтобы найти матч. В этот момент символ заменой символов будет работать, чтобы сделать своп. Капитализация может быть обработана путем проверки с помощью Char.IsUpper для исходного символа, а затем с помощью Char.ToUpper или Char.ToLower!--4--> по месту назначения в зависимости от обстоятельств.


вы можете перебирать строку как массив символов и использовать Char.IsUpper (параметр char)

  1. создать пустой строкой
  2. создать цикл перебора символов
  3. проверьте, если вам нужно изменить кодировку на другую
    1. Yes: проверьте, является ли символ верхним или нижним регистром, в зависимости от результата, поместите соответствующую букву в новую строку.
    2. Нет: Просто бросить этот символ в новую строку
  4. установите исходную строку в новую строку.

может быть, это не самый эффективный или эффектный способ делать что-то, но он прост, и он работает.

на боковом примечании: я не уверен, как вы конвертируете символы, но если вы говорите, сдвигая символы вниз по алфавиту (когда вы хотите их преобразовать) на постоянную величину, скажем, вы сдвигаете на 3. Так a - > d и E - >G или что-то в этом роде, то вы можете получить значение ASCII от символа, добавить 3 (Если вы хотите преобразовать его), а затем получить символ из значения ASCII. Как описано здесь. Вам придется делать проверки, чтобы убедиться, что вы возвращаетесь с конца алфавита. (или начало, если вы перемещаетесь влево).

Edit #1: (собирается сохранить выше)

очень большой блок кода... Прости! Это был лучший способ, который я мог придумать. то, о чем вы спрашивали. Надеюсь, кто-нибудь придумает более элегантный способ. Пожалуйста, прокомментируйте или что-нибудь, если вам нужны разъяснения!

    // (to be clear) This is Elias' (original) code modified.
    static void Main(string[] args)
    {
        string input = "As he DIDN'T ACHIEVE Success, he was fired";
        Dictionary<string, string> map = new Dictionary<string, string>();
        map.Add("didn't achieve success", "failed miserably");

        string temp = input;
        foreach (var entry in map)
        {
            string key = entry.Key;
            string value = entry.Value;
            temp = Regex.Replace(temp, key, match =>
            {
                string[] matchSplit = match.Value.Split(' ');
                string[] valueSplit = value.Split(' ');

                // Set the number of words to the lower one.
                // If they're the same, it doesn't matter.
                int numWords = (matchSplit.Length <= valueSplit.Length) 
                    ? matchSplit.Length
                    : valueSplit.Length;

                // only first letter of first word capitalized
                // only first letter of every word capitalized
                // all letters capitalized
                char[] result = value.ToCharArray(); ;
                for (int i = 0; i < numWords; i++)
                {
                    if (char.IsUpper(matchSplit[i][0]))
                    {
                        bool allIsUpper = true;
                        int c = 1;
                        while (allIsUpper && c < matchSplit[i].Length)
                        {
                            if (!char.IsUpper(matchSplit[i][c]) && char.IsLetter(matchSplit[i][c]))
                            {
                                allIsUpper = false;
                            }
                            c++;
                        }
                        // if all the letters of the current word are true, allIsUpper will be true.
                        int arrayPosition = ArrayPosition(i, valueSplit);
                        Console.WriteLine(arrayPosition);
                        if (allIsUpper)
                        {
                            for (int j = 0; j < valueSplit[i].Length; j++)
                            {
                                result[j + arrayPosition] = char.ToUpper(result[j + arrayPosition]);
                            }
                        }
                        else
                        {
                            // The first letter.
                            result[arrayPosition] = char.ToUpper(result[arrayPosition]);
                        }
                    }
                }

                return new string(result);
            }, RegexOptions.IgnoreCase);
        }
        Console.WriteLine(temp); 
    }

    public static int ArrayPosition(int i, string[] valueSplit)
    {
        if (i > 0)
        {
            return valueSplit[i-1].Length + 1 + ArrayPosition(i - 1, valueSplit);
        }
        else
        {
            return 0;
        }

        return 0;
    }

Замените один символ за раз и используйте

if(currentChar.ToString() == currentChar.ToUpper(currentChar).ToString())
{
   //replace with upper case variant 
}

это в значительной степени то, что говорил Рид. Единственный трюк заключается в том, что я не уверен, что вы должны делать, когда Find и Replace строки имеют разную длину. Поэтому я выбираю минимальную длину и использую ее...

static string ReplaceCaseInsensitive(string Text, string Find, string Replace)
{
    char[] NewText = Text.ToCharArray();
    int ReplaceLength = Math.Min(Find.Length, Replace.Length);

    int LastIndex = -1;
    while (true)
    {
        LastIndex = Text.IndexOf(Find, LastIndex + 1, StringComparison.CurrentCultureIgnoreCase);

        if (LastIndex == -1)
        {
            break;
        }
        else
        {
            for (int i = 0; i < ReplaceLength; i++)
            {
                if (char.IsUpper(Text[i + LastIndex])) 
                    NewText[i + LastIndex] = char.ToUpper(Replace[i]);
                else
                    NewText[i + LastIndex] = char.ToLower(Replace[i]);
            }
        }
    }

    return new string(NewText);
}