【问题标题】:c# replace string if it is not a substringc#如果不是子字符串则替换字符串
【发布时间】:2018-11-09 08:58:06
【问题描述】:

我正在处理文件,以便将预定义关键字列表替换为前后字符串(例如“#”和“.”),如下所示:

“Word Word2 anotherWord and some other stuff”应该变成“#Word.#Word2.#anotherWord.and some other stuff”

我的键是唯一的,并且从最长的键到最小的键都被处理过,所以我知道包含只能是已经存在的 但是,如果我有密钥包含(例如 Word2 包含 Word),并且如果我这样做了

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

我得到以下结果:

“#Word.##Word.2.#another#Word.. 以及其他一些东西”

可以肯定的是,我的方法并不可行。那么有什么方法可以确保我只替换字符串中的一个键,如果它不包含在另一个键中?我尝试了 RegExp,但没有找到正确的方法。还是有其他解决方案?

【问题讨论】:

  • 选择标签时请注意,不要选错了。
  • 请用正确的语言标记您的问题
  • 这不是字符串替换的工作方式。您可能想用另一个临时字符串替换搜索字符串,然后在所有搜索完成后再次替换所有内容。
  • 假设您有.Replace("bob", "#bob").Replace("cat", "#cat"),如果输入为bobcat cat bob cabobt bocatb,您希望得到什么结果?
  • @ScottHannen:这不是一个现实的解决方案。完成了一半的工作并声称不应该完成其余的工作与完成所需的工作不同。对于示例代码,可以有效地删除“Word2”替换,因为“Word”替换也会命中“Word2”,但如果使用不同的替换值(例如用“#Word”替换“Word”但用“@Word2”替换“Word2”)。

标签: c# replace substring


【解决方案1】:

如果性能不是关键要求,只需使用带单词边界的正则表达式:

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);
        }
    }
}

【讨论】:

  • 接近我的解决方案,它不使用正则表达式,因为我必须说实话,我只是对它们了解不够......!
【解决方案2】:

一种方法是使用

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"

但是,这首先需要您的原始文本包含大括号。

相当混乱,但您总是可以用 Replace 替换您要查找的单词,然后同时更改卷曲的反引号。可能有更好的方法可以做到这一点,但我现在想不出。

【讨论】:

  • (1) 虽然技术上可行,但使用String.Format 符号对输入值进行预格式化会有效地将输入绑定到特定实现,这不是好的设计。 (2) 这也意味着输入句子的任何人都知道所有占位符和占位符列表的顺序,这对最终用户有很多要求,并且经常违背诸如此类的自动化任务的目的。 (3) 此外,您的代码甚至不起作用,因为 String.Format 是 零索引的。
  • 这取决于原始用户需要这样做。他可能正在尝试填充现有模板,在这种情况下,这将是完美的。至于说我的代码不起作用。为您更新:p
【解决方案3】:

我建议直接实现,例如

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

【讨论】:

    【解决方案4】:

    正则表达式替代(顺序无关紧要):

    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.");
    

    【讨论】:

      【解决方案5】:

      使用两个循环的方法解决了问题,如下所示...

      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));
      }
      

      【讨论】:

        【解决方案6】:

        你可以用''分割你的字符串并循环遍历字符串数组。将数组的每个索引与替换字符串进行比较,然后在完成后将它们连接起来。

        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);
        

        【讨论】:

        • 请注意,空格可能不是唯一的分隔符。逗号、句号、分号、引号……您的答案从技术角度来看是可行的,但可能无法涵盖所有​​需要的情况。
        • 不,因为键实际上也可以是多字(同意,忘了提!)
        猜你喜欢
        • 2012-04-28
        • 2022-11-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-09
        相关资源
        最近更新 更多