【问题标题】:Avoid unwanted string replacement [duplicate]避免不必要的字符串替换[重复]
【发布时间】:2020-08-28 12:44:11
【问题描述】:

我有一个用于组装自动文件名的字符串模式。该模式可能包含几个属性,例如:

[UserName]
[ItemName]
[ItemId]

等等... 当要创建名称时,我获取属性的值并在模式中替换它们以获得所需的名称。例如:

var propertyDict = new Dictionary<string, string>()
{
     ["[UserName]"] = "John Smit",
     ["[ItemName]"] = "Berry 47",
     ["[ItemId]"] = "123456",
};

var namingPattern = "[UserName] @ [ItemName] (id: [ItemId])";

// Expected result  "John Smit @ Berry 47 (id: 123456)"

这很容易解决,只需一个 foreach 循环,我将字典键的任何匹配项替换为其各自的值:

 foreach (var kvp in propertyDict)
 {
      namingPattern = namingPattern.Replace(kvp.Key, kvp.Value);
 }

令我困扰的是用户选择了一个可能破坏逻辑的意外名称的情况。考虑以下情况:

var propertyDict = new Dictionary<string, string>()
{
     ["[UserName]"] = "[ItemName]", // Username matches with one of the placeholders
     ["[ItemName]"] = "Berry 47",
     ["[ItemId]"] = "123456",
};

var namingPattern = "[UserName] @ [ItemName] (id: [ItemId])";

// Expected result  "[ItemName] @ Berry 47 (id: 123456)"
// Actual result    "Berry 47 @ Berry 47 (id: 123456)"

我找到了一种使用 RegEx 解决此问题的方法。我的想法是在进行任何字符串替换之前匹配所有可能的占位符("\[[a-zA-Z]+\]"),然后通过首先检查匹配字符串的索引来开始替换。但是,如果将来其他人必须通过此逻辑,则阅读起来太冗长且烦人。有什么想法和建议吗? 提前致谢!

【问题讨论】:

标签: c# regex placeholder


【解决方案1】:

您可以使用Regex.Replace 一次更新所有匹配项。

这样,您就不会覆盖任何已经进行的替换:

var namingPattern = "[UserName] @ [ItemName] (id: [ItemId])";
var regexPattern = string.Join("|", propertyDict.Keys.Select(Regex.Escape));
// \[UserName]|\[ItemName]|\[ItemId]

var fileName = Regex.Replace(namingPattern, regexPattern,
    match => propertyDict[match.Value]);

为了避免必须Regex.Escape 键,您可以使用大括号:

var propertyDict = new Dictionary<string, string>()
{
     ["{UserName}"] = "John Smit",
     ["{ItemName}"] = "Berry 47",
     ["{ItemId}"] = "123456",
};

var namingPattern = "{UserName} @ {ItemName} (id: {ItemId})";
var regexPattern = string.Join("|", propertyDict.Keys);
// {UserName}|{ItemName}|{ItemId}

var fileName = Regex.Replace(namingPattern, regexPattern,
    match => propertyDict[match.Value]);

【讨论】:

  • 模式 [UserName] 将不匹配 "[UserName]",但括号中的任何字符,例如“U”或“r”。应该是string.Join("|", propertyDict.Select(Regex.Escape))
  • @KlausGütter 是的,好地方,也应该是propertyDict.Keys
猜你喜欢
  • 1970-01-01
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 2019-12-15
  • 2011-07-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-16
相关资源
最近更新 更多