簡體   English   中英

使用查找/替換和正則表達式將關鍵字替換為字符串中的 URL

[英]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:

  • 您需要在較短的階段之前替換較長的短語,以確保您不會只替換部分短語(例如“倫敦足球賽事”中的“倫敦”)。
  • 您可以將要鏈接的短語和 URL 存儲在 SortedDictionary 中,並提供IComparer<string>按長度然后按字母順序對字符串進行排序。 請注意,相同長度的字符串仍然比較不同是很重要的,否則您不能將它們都存儲在字典中。
  • 當您替換每個短語時,您應該生成將替換它的鏈接,並構建一個字典,將 ID 映射到鏈接。
  • 如果您使用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:如果您經常使用它,您可能需要考慮將其作為字符串的擴展方法。

如果你遞歸地進行替換怎么辦? 即,每次找到匹配項時,您將其替換為字典中的文本並重復該過程,但僅針對尚未匹配的文本部分。

正如其他人所說:

  1. 如果您在“倫敦足球賽事”之前替換“倫敦”,您對“倫敦足球賽事”的搜索將不會匹配“足球賽事<a href="http://etc..>倫敦<a>”
  2. 如果您在“倫敦”之前替換“倫敦足球賽事”,您將在倫敦足球賽事的現有鏈接中替換倫敦,這將為您提供鏈接中的鏈接...
  3. Dictionary is not ordered ,所以在任何一種情況下,如果你只是通過foreach ,你不能保證你會得到你想要的順序。
  4. 如果您的搜索文本也包含在您的網址中,您的代碼也會找到並替換它們- 當您使正則表達式不區分大小寫時尤其如此。
  5. 在 a 標簽的文本中包含前導空格? 這表明你在其他地方做錯了什么,並且你用“黑客”來補償它。

故事的寓意:我擔心查找和替換(即使使用正則表達式)不會削減它。

可能有更聰明的方法可以做到這一點,但在我的腦海中,這里有一些需要研究的東西,偽代碼:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM