2009-04-16 38 views
29

Có ai có bất kỳ mã C# hay (và cụm từ thông dụng nào) sẽ phân tích chuỗi và "liên kết" bất kỳ url nào có thể có trong chuỗi không?Mã C# để liên kết url trong một chuỗi

+0

này có vẻ là vấn đề với tư dựa biểu hiện kinh điển thường xuyên dung dịch. Có lẽ ai đó có thể chỉnh sửa tiêu đề để giúp người tìm kiếm tìm thấy nó? – JasonSmith

Trả lời

42

Đó là một nhiệm vụ khá đơn giản, bạn có thể đạt được nó với Regex và sẵn sàng để đi biểu thức chính quy từ:

Cái gì như:

var html = Regex.Replace(html, @"^(http|https|ftp)\://[a-zA-Z0-9\-\.]+" + 
         "\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?" + 
         "([a-zA-Z0-9\-\._\?\,\'/\\\+&%\$#\=~])*$", 
         "<a href=\"$1\">$1</a>"); 

Bạn cũng có thể quan tâm không chỉ trong việc tạo liên kết mà còn trong việc rút ngắn URL. Đây là một bài viết tốt về chủ đề này:

Xem thêm:

+1

Xin chào. Phản ứng tuyệt vời. Hầu hết các đề xuất trong bài đăng của bạn (và các liên kết) dường như hoạt động nhưng tất cả chúng dường như phá vỡ bất kỳ liên kết hiện có nào trong văn bản đang được đánh giá. –

+0

VSmith bạn có thể thử các biểu thức reg khác nhau từ regixlib.com và tìm biểu thức nào phù hợp nhất với bạn. –

+0

@VSmith: Bạn có ngụ ý rằng bạn có một chuỗi như "hello there, xem: http://www.b.com"; và bạn chỉ muốn liên kết thứ hai? –

4

Nó không phải là dễ dàng như bạn có thể đọc trong blog post by Jeff Atwood này. Rất khó để phát hiện nơi URL kết thúc.

Ví dụ, là phần dấu ngoặc của URL hay không:

  • http ​: //en.wikipedia.org/wiki/PCTools (CentralPointSoftware)
  • một URL trong ngoặc đơn (http ​: //en.wikipedia.org) văn bản khác

Trong trường hợp đầu tiên, dấu ngoặc đơn là một phần của URL. Trong trường hợp thứ hai họ không!

+1

Và như bạn có thể thấy từ các URL được liên kết trong câu trả lời này, không phải mọi người đều hiểu đúng :) – Ray

+0

Thực ra, tôi không muốn hai URL được liên kết. Nhưng có vẻ như điều này không được hỗ trợ. – M4N

+0

Biểu thức của Jeff dường như hiển thị kém trong trình duyệt của tôi, tôi tin rằng nó phải là: "\ (? \ Bhttp: // [-A-Za-z0-9 + & @ # /%? = ~ _() | !: ,.;] * [- A-Za-z0-9 + & @ # /% = ~ _() |] " –

6
protected string Linkify(string SearchText) { 
    // this will find links like: 
    // http://www.mysite.com 
    // as well as any links with other characters directly in front of it like: 
    // href="http://www.mysite.com" 
    // you can then use your own logic to determine which links to linkify 
    Regex regx = new Regex(@"\b(((\S+)?)(@|mailto\:|(news|(ht|f)tp(s?))\://)\S+)\b", RegexOptions.IgnoreCase); 
    SearchText = SearchText.Replace("&nbsp;", " "); 
    MatchCollection matches = regx.Matches(SearchText); 

    foreach (Match match in matches) { 
     if (match.Value.StartsWith("http")) { // if it starts with anything else then dont linkify -- may already be linked! 
      SearchText = SearchText.Replace(match.Value, "<a href='" + match.Value + "'>" + match.Value + "</a>"); 
     } 
    } 

    return SearchText; 
} 
+0

Chúc mừng bạn đã đăng bài đó :) –

+0

Chúng tôi đã kết thúc bằng cách sử dụng một cái gì đó rất giống nhau, với một sửa đổi. Chúng tôi đã kết thúc đảm bảo rằng sự thay thế chỉ xảy ra một lần. Điều này có nghĩa là chúng tôi sẽ mất một số liên kết (liên kết xảy ra nhiều lần) nhưng loại bỏ khả năng bị cắt xén các liên kết trong hai trường hợp: 1) Khi có hai liên kết trong đó có nhiều chi tiết hơn liên kết kia. ví dụ: "http://google.com http://google.com/reader" 2) Khi có kết hợp các liên kết HTML với các liên kết văn bản thuần túy. ví dụ: "Http://google.com Google" if (input.IndexOf (match.Value) == input.LastIndexOf (match.Value)) { ... } –

10

tốt, sau rất nhiều nghiên cứu về vấn đề này, và nhiều nỗ lực để sửa chữa lần khi

  1. người nhập http://www.sitename.com và www.sitename.com trong cùng một bài
  2. bản sửa lỗi cho parenthisis tương tự (http://www.sitename.com) và http://msdn.microsoft.com/en-us/library/aa752574(vs.85).aspx
  3. url dài như: http://www.amazon.com/gp/product/b000ads62g/ref=s9_simz_gw_s3_p74_t1?pf_rd_m=atvpdkikx0der&pf_rd_s=center-2&pf_rd_r=04eezfszazqzs8xfm9yd&pf_rd_t=101&pf_rd_p=470938631&pf_rd_i=507846

chúng tôi hiện đang sử dụng tiện ích HtmlHelper này ...nghĩ tôi sẽ chia sẻ và nhận được bất kỳ nhận xét nào:

private static Regex regExHttpLinks = new Regex(@"(?<=\()\b(https?://|www\.)[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|](?=\))|(?<=(?<wrap>[=~|_#]))\b(https?://|www\.)[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|](?=\k<wrap>)|\b(https?://|www\.)[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|]", RegexOptions.Compiled | RegexOptions.IgnoreCase); 

    public static string Format(this HtmlHelper htmlHelper, string html) 
    { 
     if (string.IsNullOrEmpty(html)) 
     { 
      return html; 
     } 

     html = htmlHelper.Encode(html); 
     html = html.Replace(Environment.NewLine, "<br />"); 

     // replace periods on numeric values that appear to be valid domain names 
     var periodReplacement = "[[[replace:period]]]"; 
     html = Regex.Replace(html, @"(?<=\d)\.(?=\d)", periodReplacement); 

     // create links for matches 
     var linkMatches = regExHttpLinks.Matches(html); 
     for (int i = 0; i < linkMatches.Count; i++) 
     { 
      var temp = linkMatches[i].ToString(); 

      if (!temp.Contains("://")) 
      { 
       temp = "http://" + temp; 
      } 

      html = html.Replace(linkMatches[i].ToString(), String.Format("<a href=\"{0}\" title=\"{0}\">{1}</a>", temp.Replace(".", periodReplacement).ToLower(), linkMatches[i].ToString().Replace(".", periodReplacement))); 
     } 

     // Clear out period replacement 
     html = html.Replace(periodReplacement, "."); 

     return html; 
    } 
1

đã tìm thấy sau biểu thức chính quy http://daringfireball.net/2010/07/improved_regex_for_matching_urls

đối với tôi có vẻ rất tốt. Giải pháp Jeff Atwood không xử lý nhiều trường hợp. josefresno dường như tôi xử lý tất cả các trường hợp. Nhưng khi tôi đã cố gắng để hiểu nó (trong trường hợp của bất kỳ yêu cầu hỗ trợ) bộ não của tôi đã được đun sôi.

1

Có lớp:

public class TextLink 
{ 
    #region Properties 

    public const string BeginPattern = "((http|https)://)?(www.)?"; 

    public const string MiddlePattern = @"([a-z0-9\-]*\.)+[a-z]+(:[0-9]+)?"; 

    public const string EndPattern = @"(/\S*)?"; 

    public static string Pattern { get { return BeginPattern + MiddlePattern + EndPattern; } } 

    public static string ExactPattern { get { return string.Format("^{0}$", Pattern); } } 

    public string OriginalInput { get; private set; } 

    public bool Valid { get; private set; } 

    private bool _isHttps; 

    private string _readyLink; 

    #endregion 

    #region Constructor 

    public TextLink(string input) 
    { 
     this.OriginalInput = input; 

     var text = Regex.Replace(input, @"(^\s)|(\s$)", "", RegexOptions.IgnoreCase); 

     Valid = Regex.IsMatch(text, ExactPattern); 

     if (Valid) 
     { 
      _isHttps = Regex.IsMatch(text, "^https:", RegexOptions.IgnoreCase); 
      // clear begin: 
      _readyLink = Regex.Replace(text, BeginPattern, "", RegexOptions.IgnoreCase); 
      // HTTPS 
      if (_isHttps) 
      { 
       _readyLink = "https://www." + _readyLink; 
      } 
      // Default 
      else 
      { 
       _readyLink = "http://www." + _readyLink; 
      } 
     } 
    } 

    #endregion 

    #region Methods 

    public override string ToString() 
    { 
     return _readyLink; 
    } 

    #endregion 
} 

Sử dụng nó trong phương pháp này:

public static string ReplaceUrls(string input) 
{ 
    var result = Regex.Replace(input.ToSafeString(), TextLink.Pattern, match => 
    { 
     var textLink = new TextLink(match.Value); 
     return textLink.Valid ? 
      string.Format("<a href=\"{0}\" target=\"_blank\">{1}</a>", textLink, textLink.OriginalInput) : 
      textLink.OriginalInput; 
    }); 
    return result; 
} 

trường hợp thử nghiệm:

[TestMethod] 
public void RegexUtil_TextLink_Parsing() 
{ 
    Assert.IsTrue(new TextLink("smthing.com").Valid); 
    Assert.IsTrue(new TextLink("www.smthing.com/").Valid); 
    Assert.IsTrue(new TextLink("http://smthing.com").Valid); 
    Assert.IsTrue(new TextLink("http://www.smthing.com").Valid); 
    Assert.IsTrue(new TextLink("http://www.smthing.com/").Valid); 
    Assert.IsTrue(new TextLink("http://www.smthing.com/publisher").Valid); 

    // port 
    Assert.IsTrue(new TextLink("http://www.smthing.com:80").Valid); 
    Assert.IsTrue(new TextLink("http://www.smthing.com:80/").Valid); 
    // https 
    Assert.IsTrue(new TextLink("https://smthing.com").Valid); 

    Assert.IsFalse(new TextLink("").Valid); 
    Assert.IsFalse(new TextLink("smthing.com.").Valid); 
    Assert.IsFalse(new TextLink("smthing.com-").Valid); 
} 

[TestMethod] 
public void RegexUtil_TextLink_ToString() 
{ 
    // default 
    Assert.AreEqual("http://www.smthing.com", new TextLink("smthing.com").ToString()); 
    Assert.AreEqual("http://www.smthing.com", new TextLink("http://www.smthing.com").ToString()); 
    Assert.AreEqual("http://www.smthing.com/", new TextLink("smthing.com/").ToString()); 

    Assert.AreEqual("https://www.smthing.com", new TextLink("https://www.smthing.com").ToString()); 
} 
+0

này hoạt động tốt, tuy nhiên nó phù hợp trên những thứ như o.context hoặc chuỗi khác có dấu chấm trong chúng. Sẽ được tốt đẹp để buộc .com/.org/.net vv, một nơi nào đó trong chuỗi –

+0

Ngoài ra nó buộc www, mà không phải là luôn luôn như vậy. –

Các vấn đề liên quan