Как решить строку заменить фиаско - PullRequest
1 голос
/ 13 июля 2011

ПРИМЕЧАНИЕ : Моя проблема НЕ в том, что мои ссылки не заменяются. Но это NESTED . например, это комментарий

some string with www.google.com/blah/blah also something else www.google.com

к моменту замены второй строки часть первой также действительна ( www.google.com / бла / бла), поэтому она заменяет эту ссылку дважды.

У меня есть веб-приложение, которое позволяет пользователям комментировать. Я обрабатываю входную строку и преобразую все ссылки в формат ссылки html , когда отображаю ее на странице . Исходная строка ввода пользователя остается в БД и ничего не происходит, поэтому она не повреждена при обработке. Просто когда я показываю это на странице, я выполняю свою функцию на этом.

Теперь эту логику я использую, чтобы заменить все ссылки на их HTML-форматы

  1. Regex все ссылки
  2. Для каждого совпадения замените ссылку на версию в формате html в исходной строке.
  3. Наконец, отобразить строку.

ex: www.google.com становится <a href="http://www.google.com" target="_blank">www.google.com</a> непосредственно перед отображением на странице.

До недавнего времени это работало отлично, один из моих клиентов разместил контент с двумя ссылками из одного домена.

ссылки были, скажем,

  1. www.google.com / изображения / blahblah
  2. www.google.com

Моя проблема в том, что когда во второй раз выполняется замена строки (я использую StringBuilder.Replace), первая ссылка также заменяется!

Итак, во-первых,

www.google.com/images/blahblah

становится

<a href="http://www.google.com/images/blahblah" target="_blank">www.google.com/image/blahblah</a>

что хорошо. Но проблема возникает при замене второй строки, так как замена глобальна, она выполняет замену уже обработанной ссылки, поэтому исходная (указанная выше) ссылка искажается, так как видит там также www.google.com .

Это так запутано, что я действительно получаю изуродованную мерзость струны.

Как мне этого избежать?

Предоставляет ли Regex.Matches индекс совпадающего элемента, с которым я могу работать? Я нигде не мог его найти.

С чем лучше всего бороться? какие-либо предложения?

извините за длинный вопрос.

Я могу сделать это, вручную перебирая строку, но это долго и больно, должен быть хороший способ сделать это ...

edit добавление дополнительной информации по запросу:

Мое регулярное выражение:

    string rPattern = @"(((http|ftp|https):\/\/)|www\.)[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#!]*[\w\-\@?^=%&amp;/~\+#])?";

     Regex rLinks = new Regex(rPattern, RegexOptions.IgnoreCase);
     MatchCollection matches = rLinks.Matches(inputString);

тогда я использую

foreach(Match match in matches)
{
    if(match.value.StartsWith("www.youtube.com/watch"))
    {
         //logic to embed youtube video - this works fine.
    } 
}

//Here I replace all hyperlinks to their <a href> parts

Ответы [ 4 ]

3 голосов
/ 13 июля 2011

Regex.Matches возвращает MatchCollection. Match.Index Это то, что вы ищете.

string pattern = @"(https?://)?(?:www(?:\.\w+)+|(?:\w+\.)+(?:com|org|us|net|...))(/\w*)*"; // your pattern here.
foreach (Match match in Regex.Matches (input, pattern))
{
   // Use match.Index and match.Length;
}

Но на самом деле, вы, вероятно, ищете что-то похожее на это:

string originalPost = 
   @"Ooh shiney: www.google.com/images/blahblah
   Look here: www.google.com";

string html = Regex.Replace (
   originalPost, patternString, 
   "<a href='http://$1' target='_blank'>$1</a>");

Или вы можете использовать matchEvaluator для более сложной работы (например, убедитесь, что мы не добавляем двойной http: //.

string html = Regex.Replace (
   originalPost, patternString, 
   m => 
      string.Format (
         "<a href='{0}{1}' target='_blank'>{1}</a>",
          m.Value.StartsWith ("http", StringComparison.IgnoreCase) ? "" : "http://",
          m.Value));
2 голосов
/ 13 июля 2011

У меня была такая же потребность, и вот что я использую последние пару лет:

public static string MakeCommentSafe(string strComment)
{
    // Replace carriage return / line feeds with line feeds.  Then HtmlEncode.  Then replace multiple consecutive line feeds with single line feeds.
    strComment = Regex.Replace(System.Web.HttpContext.Current.Server.HtmlEncode(Regex.Replace(strComment, "\r\n", "\n").Replace((char)13, (char)10)), "\n(\n)+", "$1\n");

    // Find all links and make them active
    return Regex.Replace(Regex.Replace(strComment, @"((https?|ftp|gopher|telnet|file|notes|ms-help):((//)|(\\\\))+[\w\d:#@%/;$()~_?\+-=\\\.&]*)", "<a href=\"$1\" target=\"_blank\" rel=\"nofollow\">$1</a>"), "\n", "<br />");
}

А вот и совет. Если вы действительно хотите, чтобы это работало хорошо с большим количеством комментариев на странице, сохраните небезопасные и безопасные версии в базе данных, когда комментарий будет опубликован. Таким образом, вам не нужно будет повторно вызывать эту функцию при отображении каждого комментария на странице.

0 голосов
/ 13 июля 2011

Чтобы играть в дьяволов, защитник:

Итак, вы хотите исправить строки, которые выглядят так:

www.example.com
www.example.com/foo/bar
www.example.co.tw/baz.moo?foo=1

, но не строки, которые выглядят так:

www.example.com www.example.com/foo/bar www.example.co.tw/baz.moo?foo=1

Я бы предположил, что я прав.Простое решение, разверните свое регулярное выражение так, чтобы оно выглядело по обе стороны от объекта, похожего на URL, и игнорируйте его, если оно:

  1. Между href=" и " target="_blank">
  2. Между " target="_blank"> и </a>
0 голосов
/ 13 июля 2011

Используйте Regex.Replace метод, например ::

var result = Regex.Replace(input, pattern, "<a href=\"$0\" target=\"_blank\">$0</a>");
...