c # заменить строку, если она не является подстрокой - PullRequest
0 голосов
/ 30 мая 2018

Я обрабатываю файлы, чтобы заменить список предопределенных ключевых слов пре- и постстрокой (скажем, "#" и "."), Например:

"Word Word2 anotherWord и некоторые другие вещи "должны стать" #Word. # Word2. #AnotherWord. И некоторые другие вещи "

Мои ключи уникальны и обрабатывают ключи от самых длинных до самых маленьких, поэтому яЯ знаю, что включение может быть только уже. Однако, если у меня есть включение ключа (например, Word2 содержит Word), и если я сделаю

"Word Word2 anotherWord and some other stuff"
    .Replace("anotherWord", "#anotherWord.")
    .Replace("Word2", "#Word2.")
    .Replace("Word", "#Word.")

, я получу следующий результат:

"# Слово. ## Word.2. # Другое # Слово .. и некоторые другие вещи"

Конечно, мой подход не работает.Так как же убедиться, что я заменю только ключ в строке, если он НЕ содержится в другом ключе?Я попробовал RegExp, но не нашел правильный путь.Или есть другое решение?

Ответы [ 6 ]

0 голосов
/ 31 мая 2018

Решил проблему, используя двухконтурный подход следующим образом ...

List<string> keys = new List<string>();
keys.Add("Word1"); // ... and so on
// IMPORTANT: algorithm works only when we are sure that one key cannot be
//            included in another key with higher index. Also, uniqueness is
//            guaranteed by construction, although the routine would work
//            duplicate key...!
keys = keys.OrderByDescending(x => x.Length).ThenBy(x => x).ToList<string>();
// first loop: replace with some UNIQUE key hash in text
foreach(string key in keys) {
  txt.Replace(key, string.Format("!#someUniqueKeyNotInKeysAndNotInTXT_{0}_#!", keys.IndexOf(key)));
}
// second loop: replace UNIQUE key hash with corresponding values...
foreach(string key in keys) {
  txt.Replace(string.Format("!#someUniqueKeyNotInKeysAndNotInTXT_{0}_#!", keys.IndexOf(key)), string.Format("{0}{1}{2}", preStr, key, postStr));
}
0 голосов
/ 30 мая 2018

Альтернативное выражение (порядок не имеет значения):

var result = Regex.Replace("Word Word2 anotherWord and some other stuff", @"\b\S+\b", m => 
    m.Value == "anotherWord" ? "#anotherWord." : 
    m.Value == "Word2" ? "#Word2." :
    m.Value == "Word" ? "#Word." : m.Value)

Или отдельно:

string s = "Word Word2 anotherWord and some other stuff";

s = Regex.Replace(s, @"\b" + Regex.Escape("anotherWord") + @"\b", "#anotherWord.");
s = Regex.Replace(s, @"\b" + Regex.Escape("Word2")       + @"\b", "#Word2.");
s = Regex.Replace(s, @"\b" + Regex.Escape("Word")        + @"\b", "#Word.");
0 голосов
/ 30 мая 2018

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

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Subst
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var map = new Dictionary<string, string>{
                {"Word", "#Word."},
                {"anotherWord", "#anotherWord."},
                {"Word2", "#Word2."}
            };
            var input = "Word Word2 anotherWord and some other stuff";

            foreach(var mapping in map) {
                input = Regex.Replace(input, String.Format("\\b{0}\\b", mapping.Key), Regex.Escape(mapping.Value));
            }

            Console.WriteLine(input);
        }
    }
}
0 голосов
/ 30 мая 2018

Я предлагаю прямая реализация , например

private static String MyReplace(string value, params Tuple<string, string>[] substitutes) {
  if (string.IsNullOrEmpty(value))
    return value;
  else if (null == substitutes || !substitutes.Any())
    return value;

  int start = 0;
  StringBuilder sb = new StringBuilder();

  while (true) {
    int at = -1;
    Tuple<string, string> best = null;

    foreach (var pair in substitutes) {
      int index = value.IndexOf(pair.Item1, start);

      if (index >= 0)  
        if (best == null || 
            index < at || 
            index == at && best.Item1.Length < pair.Item1.Length) { 
          at = index;
          best = pair;
        }
    }

    if (best == null) {
      sb.Append(value.Substring(start));

      break;
    }

    sb.Append(value.Substring(start, at - start));
    sb.Append(best.Item2);
    start = best.Item1.Length + at;
  }

  return sb.ToString();
}

Тест

  string source = "Word Word2 anotherWord and some other stuff";

  var result = MyReplace(source, 
    new Tuple<string, string>("anotherWord", "#anotherWord."),
    new Tuple<string, string>("Word2", "#Word2."),
    new Tuple<string, string>("Word", "#Word."));

 Console.WriteLine(result);

Результат:

 #Word. #Word2. #anotherWord. and some other stuff
0 голосов
/ 30 мая 2018

Вы можете разделить вашу строку на '' и циклически перебирать массив строк.Сравните каждый индекс массива со строками замены и затем объедините их, когда закончите.

string newString = "Word Word2 anotherWord and some other stuff";
string[] split = newString.Split(' ');

foreach (var s in split){
    if(s == "Word"){
        s = "#Word";
    } else if(s == "Word2"){
        s = "#Word2";
    } else if(s == "anotherWord"){
        s = "#anotherWord";
    }
}
string finalString = string.Concat(split);
0 голосов
/ 30 мая 2018

Одним из способов является использование

string myString = String.Format("ORIGINAL TEXT {1} {2}", "TEXT TO PUT INSIDE CURLY BRACKET 1", "TEXT TO PUT IN CURLY BRACKET 2");

//Result: "ORIGINAL TEXT TEXT TO PUT INSIDE CURLY BRACKET 1 TEXT TO PUT IN CURLY BRACKET 2"

Однако для этого требуется, чтобы ваш исходный текст содержал фигурные скобки внутри.

Довольно грязно, но вы всегда можете заменитьслова, которые вы ищете с Заменить, а затем изменить фигурные backets в то же время.Вероятно, есть гораздо лучший способ сделать это, но я не могу сейчас об этом думать.

...