我正在开发一个基于web的帮助系统,它将自动将链接插入到解释性文本中,将用户带到帮助中的其他主题。我有数百个应该联系的术语,即
“手册和标签”(一般描述这些概念)“删除手册和标签”(描述这一特定行动)“了解关于添加手册和标签的更多信息”(同样,更具体的操作)
我有一个RegEx来查找/替换整个单词(good ol‘\b),这非常有用,除了在其他链接术语中找到的链接术语之外。而不是:
<a href="#">Learn more about manuals and labels</a>我最后
<a href="#">Learn more about <a href="#">manuals and labels</a></a>这让每个人都哭了一点。改变替换术语的顺序(最短到最长)意味着我将得到:
Learn more about <a href="#">manuals and labels</a>没有外部链接我真的需要。
更复杂的是搜索词的大写化可能会有所不同,我需要保留原来的大写。如果我能做这样的事,我就准备好了:
Regex _regex = new Regex("\\b" + termToFind + "(|s)" + "\\b", RegexOptions.IgnoreCase);
string resultingText = _regex.Replace(textThatNeedsLinksInserted, "<a>" + "$&".Replace(" ", "_") + "</a>));然后,在所有的条件完成后,删除"_",这将是完美的。"Learn_more_about_manuals_and_labels“不符合”手册和标签“,一切都很好。
在编写文本时,帮助作者划分需要替换的术语是很困难的--他们不习惯编码。此外,这将限制以后添加新术语的灵活性,因为我们必须返回并在所有以前编写的文本中添加分隔符。
是否有一个允许我在原始匹配中用"_“替换空白的RegEx?还是有不同的解决方案在逃避我?
发布于 2013-10-11 16:45:53
从使用嵌套链接的示例中可以看出,您正在对这些术语进行单独传递,并执行多个Regex.Replace调用。因为您使用的是正则表达式,所以您应该让它完成繁重的任务,并将一个很好的模式组合在一起,从而利用交互。
换句话说,您可能需要这样的模式:\b(term1|term2|termN)\b
var input = "Having trouble with your manuals and labels? Learn more about adding manuals and labels. Need to get rid of them? Try to delete manuals and labels.";
var terms = new[]
{
"Learn more about adding manuals and labels",
"Delete Manuals and Labels",
"manuals and labels"
};
var pattern = @"\b(" + String.Join("|", terms) + @")\b";
var replacement = @"<a href=""#"">$1</a>";
var result = Regex.Replace(input, pattern, replacement, RegexOptions.IgnoreCase);
Console.WriteLine(result);现在,为了解决每个术语对应的href值的问题,您可以使用字典并将regex更改为使用MatchEvaluator,它将返回自定义格式并从字典中查找值。字典还通过传入StringComparer.OrdinalIgnoreCase来忽略大小写。我稍微调整了模式,在组的开头添加了?:,使其成为一个非捕获组,因为我不再像在第一个示例中那样引用捕获的项。
var terms = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ "Learn more about adding manuals and labels", "2.html" },
{ "Delete Manuals and Labels", "3.html" },
{ "manuals and labels", "1.html" }
};
var pattern = @"\b(?:" + String.Join("|", terms.Select(t => t.Key)) + @")\b";
var result = Regex.Replace(input, pattern,
m => String.Format(@"<a href=""{0}"">{1}</a>", terms[m.Value], m.Value),
RegexOptions.IgnoreCase);
Console.WriteLine(result);发布于 2013-10-11 16:54:01
我会使用这样的有序字典,确保最小的术语是最后一个:
using System;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
public class Test
{
public static void Main()
{
OrderedDictionary Links = new OrderedDictionary();
Links.Add("Learn more about adding manuals and labels", "2");
Links.Add("Delete Manuals and Labels", "3");
Links.Add("manuals and labels", "1");
string text = "Having trouble with your manuals and labels? Learn more about adding manuals and labels. Need to get rid of them? Try to delete manuals and labels.";
foreach (string termToFind in Links.Keys)
{
Regex _regex = new Regex(@"\b" + termToFind + @"s?\b(?![^<>]*</)", RegexOptions.IgnoreCase);
text = _regex.Replace(text, @"<a href=""" + Links[termToFind] + @".html"">$&</a>");
}
Console.WriteLine(text);
}
}我添加的负展望((?![^<>]*</))阻止了替换之前已经替换过的部分,该部分位于锚标记之间。
发布于 2013-10-11 15:36:17
首先,可以通过使用manuals and labels防止Regex查找Learn more about manuals and labels。修改您的正则表达式如下所示:
(?<!Learn more about )(manuals and labels)如果不是你的具体要求,我会提出一个不同的解决方案。您应该为正则表达式定义规则或优先级列表,或者两者都定义。一个可能的规则可以是“始终先搜索匹配最多字符的正则表达式”。然而,这需要您的regexs始终是固定长度。而且,它也不能阻止一个正则表达式使用和替换其他正则表达式(甚至可能是相同大小的)所匹配的字符。
当然,您需要为每个regexs添加一个额外的回顾和展望,以避免替换替换元素中的字符串。
https://stackoverflow.com/questions/19321459
复制相似问题