[英]Using find/replace and regex to replace keywords with URLs in a string
我有我想用一些 URL 替換的關鍵字列表(單個詞或幾個詞)。
喜歡:
倫敦將被<a href="http://www.mysite/london-events/london">London</a>
取代
<a href="http://www.mysite/footbal-events/london"> Football events in London</a>
<a href="http://www.mysite/footbal-events/london"> London football events</a>
的倫敦足球賽事
倫敦足球賽事<a href="http://www.mysite/footbal-events/london"> Football events London</a>
<a href="http://www.mysite/party-sites/london"> party sites in London</a>
<a href="http://www.mysite/party-sites/london"> London party sites</a>
的倫敦派對網站
我在字典中放置了鍵/值,鍵中的關鍵字和值中的 URL 並替換為
內容如下:
倫敦是一座偉大的城市,在倫敦舉辦足球賽事,但倫敦的派對場所也不錯。 倫敦足球賽事和倫敦派對場地都很棒。 享受倫敦!
替換鍵/值的代碼:
private static string ParsedContents(some arguments list here...)
{
Dictionary<string, string> keyWords = GetKeywordsAndEntityWithURL(some arguments list here...);
StringBuilder parsedContents = new StringBuilder(contents);
foreach (var keyWord in keyWords)
{
string replacedString = Regex.Replace(parsedContents.ToString(), "\\b" + keyWord.Key + "\\b", keyWord.Value, RegexOptions.IgnoreCase);
parsedContents.Remove(0, parsedContents.Length);
parsedContents.Append(replacedString);
}
// retrun parsed contents as string.
return parsedContents.ToString();
}
當我運行我的代碼時,只有 'London' 替換為'<a href="http://www.mysite/london-events/london">London</a>'
並且所有其他都保持不變,但如果我刪除 ' London' 來自關鍵字它工作正常。
你能幫我看看如何匹配整個字符串。
要替換的內容和網址是假的:
謝謝
因為您要鏈接的某些短語包含您要鏈接的其他短語,並且鏈接本身也會包含這些短語,如果您想避免棘手的正則表達式,您必須分兩個階段進行:
第 1 階段:將每個短語替換為與其他任何內容都不匹配的短語的唯一 ID:
IComparer<string>
按長度然后按字母順序對字符串進行排序。 請注意,相同長度的字符串仍然比較不同是很重要的,否則您不能將它們都存儲在字典中。string.Replace
替換短語,您需要將僅區分大小寫的短語視為不同的短語,即“倫敦的派對網站”與“倫敦的派對網站”不同,並且每個都需要有一個單獨的 ID .第 2 階段:將所有占位符 ID 替換為生成的鏈接。
這是一個 class 來做到這一點:
class TextLinker : IComparer<string>
{
private SortedDictionary<string, string> phrasesToUrls;
public TextLinker()
{
// Pass self as IComparer to sort dictionary using Compare method.
phrasesToUrls = new SortedDictionary<string, string>(this);
}
public void AddLink(string phrase, string URL)
{
phrasesToUrls.Add(phrase, URL);
}
public string Link(string text)
{
// phase 1: replace phrases to be linked with unique placeholders
Dictionary<string, string> placeholdersToLinks =
new Dictionary<string, string>();
foreach (KeyValuePair<string, string> pair in phrasesToUrls)
{
// Replace phrases with placeholders.
string placeholder = Guid.NewGuid().ToString();
text = text.Replace(pair.Key, placeholder);
// Create dictionary of links by placeholder
string link = string.Format(
"<a href=\"{0}\">{1}</a>",
pair.Value,
pair.Key);
placeholdersToLinks.Add(placeholder, link);
}
// Phase 2: replace unique placeholders with links.
foreach (KeyValuePair<string, string> pair in placeholdersToLinks)
{
text = text.Replace(pair.Key, pair.Value);
}
return text;
}
public int Compare(string x, string y)
{
if (x.Length > y.Length) return -1;
if (x.Length < y.Length) return +1;
// Equal length strings still need to be differentiated, otherwise
// they will be treated as the same key by the dictionary.
return x.CompareTo(y);
}
}
這是它的使用示例:
string input = "London is a great city and have football events " +
"in London but party sites in London are also good. London " +
"football events are great along with London party sites. " +
"Enjoy London!";
TextLinker linker = new TextLinker();
linker.AddLink(
"Football events in London",
"http://www.mysite/footbal-events/london");
linker.AddLink(
"football events in London",
"http://www.mysite/footbal-events/london");
linker.AddLink(
"London football events",
"http://www.mysite/footbal-events/london");
linker.AddLink(
"London",
"http://www.mysite/london-events/london");
linker.AddLink(
"Party sites in London",
"http://www.mysite/party-sites/london");
linker.AddLink(
"party sites in London",
"http://www.mysite/party-sites/london");
linker.AddLink(
"London party sites",
"http://www.mysite/party-sites/london");
string output = linker.Link(input);
您還可以重載AddLink
方法以自動生成具有替代大小寫的短語。
如果您首先用 URL 替換所有較長的字符串,而不是在 URL 中設置“London”,而是可以設置其他詞,例如“Lxondon”,該怎么辦? 將所有包含 London 的字符串替換為其對應的 URL 后,您也可以將 London 替換為其 URI。 最后,您將在所有文本中將“Lxondon”替換為“London”。
這不是一個很好的方法,但我認為它會起作用。
要詳細說明其他答案,您必須首先放置最長和更復雜的字符串替換。 例如。
倫敦的足球賽事
倫敦
如果您像示例中那樣做倫敦,並將其替換為肯特,則“倫敦足球賽事”的任何實例都將變為“肯特足球賽事”,並且不會滿足正則表達式。
PS:如果您經常使用它,您可能需要考慮將其作為字符串的擴展方法。
如果你遞歸地進行替換怎么辦? 即,每次找到匹配項時,您將其替換為字典中的文本並重復該過程,但僅針對尚未匹配的文本部分。
正如其他人所說:
foreach
,你不能保證你會得到你想要的順序。故事的寓意:我擔心查找和替換(即使使用正則表達式)不會削減它。
可能有更聰明的方法可以做到這一點,但在我的腦海中,這里有一些需要研究的東西,偽代碼:
while(!input.EOS)
for(longest to shortest key)
if(input.indexOf(key) = 0)
output += input.replace(key, url)
input = remained of input
matched = true
if !matched then move first word from input to output
您將不得不稍微擺弄一下,尤其是因為空格問題(如何/在哪里匹配空格和非單詞字符?)這是另一個幫助您入門的提示: ^\s*(.+?)\s*\b
您可以做的一件事是:
將鍵(從大到小)連接成一個正則表達式(假設這里的dictionary
是一個IDictionary<string, string>
):
var pattern = string.Join(
"|",
dictionary.Keys.OrderByDescending(k => k.Length).Select(Regex.Escape).ToArray()
);
var regex = new Regex("(" + pattern + ")", RegexOptions.ExplicitCapture);
注意Regex.Escape
在轉換 function 中的使用:我們不希望鍵中有特殊的正則表達式字符來搞砸事情。
一項快速測試表明,.NET 的正則表達式引擎將按照它們在模式中出現的順序嘗試匹配。 這意味着,當正確排序時,將首先嘗試較長的鍵,然后正則表達式將繼續前進,尋找新的匹配項。
然后,您可以像 go 一樣遍歷匹配項並從舊字符串構建一個新字符串,而不是多次掃描輸入字符串。 這兩種技術相結合將消除這兩個問題:過早匹配和重復匹配。
string input = "..."; // This is your input string.
int last = 0;
var output = new StringBuilder(input.Length);
foreach (Match match in regex.Matches(input)) {
output.Append(input.Substring(last, match.Index - last); // Appends text between matches.
output.AppendFormat(
"<a href=\"{1}\">{0}</a>",
match.Value,
dictionary[match.Value]
);
last = match.Index + match.Length; // Moves the index to the end of this match.
}
不包括錯誤檢查。 此外,正則表達式本身可能會受益於 \ \b(...)\b
\b
錨。 不過,這是未經測試的,我要睡覺了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.