Превратить заголовок в пунктирную строку, удобную для URL

18

Я хотел бы написать метод C #, который преобразует любой заголовок в URL-строку, похожую на то, что делает stackoverflow:

  • заменить пробелы тире
  • удалить скобки
  • и др.

Я собираюсь удалить зарезервированные символы согласно стандарту RFC 3986 (из Wikipedia ), но я не знаю, Знаете, хватит ли этого? Это сделает ссылки работоспособными, но кто-нибудь знает, какие другие символы заменяются здесь в stackoverflow? Я не хочу, чтобы в моих URL-адресах попадали% -s ...

Текущая реализация

string result = Regex.Replace(value.Trim(), @"[!*'""'();:@&+=$,/\?%#\[\]<>«»{}_]");
return Regex.Replace(result.Trim(), @"[\s*[\-–—\s]\s*]", "-");

Мои вопросы

  1. Какие символы следует удалить?
  2. Должен ли я ограничивать максимальную длину результирующей строки?
  3. Кто-нибудь знает, какие правила применяются к названиям здесь на SO?

Под-вопрос
Должен ли я переместить этот вопрос в мета, хотя это связано с программированием?

    
задан Robert Koritnik 29.01.2010 в 12:51
источник
  • FWIW, не думайте, что это мета, вы просто используете SO в качестве примера. –  T.J. Crowder 29.01.2010 в 12:53

7 ответов

35

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

return Regex.Replace(value, @"[^A-Za-z0-9_\.~]+", "-");

(Обратите внимание, что я не включил тире в список разрешенных символов, поэтому он сжимается оператором «1 или более» [ + ], поэтому несколько тире (в исходном или сгенерированном или комбинация) свертываются, как замечательная точка Доминика Роджер.)

Вы также можете удалить общие слова («the», «an», «a» и т. д.), хотя это может слегка изменить смысл предложения. Вероятно, вы хотите удалить любые трейлинг-тире и периоды.

Также настоятельно рекомендуем делать то, что делают SO и другие, и включать уникальный идентификатор other , чем заголовок, а затем использовать только этот уникальный идентификатор при обработке URL-адреса. Итак, http://example.com/articles/1234567/is-the-pop-catholic (обратите внимание на недостающие «e») и http://example.com/articles/1234567/is-the-pope-catholic на тот же ресурс.

    
ответ дан T.J. Crowder 29.01.2010 в 12:57
  • Однако использование белого списка не позволяет символам Unicode (в IRI) проходить через. –  bobince 29.01.2010 в 13:26
  • @Bobince: Точно. Я должен также предоставить наши символы, связанные с языком (из восточно-европейской кодировки) –  Robert Koritnik 29.01.2010 в 14:00
  • @Robert: IRI (RFC3987; ietf.org/rfc/rfc3987.txt) изменяет игру. Если это важно, вы можете упомянуть об этом в своем вопросе. Не похоже, что добавить поддерживаемые значения IRI в белый список сложно. Для сильных взглядов вы можете предварительно фильтровать их. –  T.J. Crowder 29.01.2010 в 14:06
  • @TJCrowder: не следует. (точка) в вашем шаблоне регулярных выражений? –  Robert Koritnik 29.01.2010 в 15:14
  • @ Robert: Я так не думаю, но, честно говоря, я не уверен и должен был проверить. Это безопасно, поэтому я отредактировал ответ. Обычное значение точки (любой символ здесь) не имеет никакого смысла в конструкции класса символов. Вы должны бежать '(очевидно), - (поскольку он создает диапазон внутри конструкции) и] (который закрывает его), но я не думаю, что вам нужно избегать большинства других. –  T.J. Crowder 29.01.2010 в 15:45
Показать остальные комментарии
2

Я бы делал:

string url = title;
url = Regex.Replace(url, @"^\W+|\W+$", "");
url = Regex.Replace(url, @"'\"", "");
url = Regex.Replace(url, @"_", "-");
url = Regex.Replace(url, @"\W+", "-");

В основном, что это делает:

  • разделяет символы без слова с начала и конца заголовка;
  • удаляет одинарные и двойные кавычки (в основном, чтобы избавиться от апострофов в середине слов);
  • заменяет символы подчеркивания дефисом (символы подчеркивания являются технически символом слова вместе с цифрами и буквами); и
  • заменяет все группы символов, отличных от слова, на один дефис.
ответ дан cletus 29.01.2010 в 12:57
  • Мне интересно, почему это не получило больше голосов? Очень просто понять и объяснить. Я также задаюсь вопросом, может ли String.Replace быть быстрее для шагов 2 и 3, которые заменяют литеральные символы, но это здесь и не существует. Меня также интересует, как символ несловного символа ^ \ W выполняется с юникодными и нелатинскими языками? Если он справится с ними даже немного хорошо, я бы сказал, что это лучший ответ партии. Окончательное предложение - мне нравится более раннее предложение о замене «&» на «и». –  Dave Amphlett 08.09.2012 в 14:56
  • О - последняя вещь, я думаю, что в третьей строке (вторая .Replace) @ "'\" "на самом деле должна быть @" "" "" –  Dave Amphlett 08.09.2012 в 15:01
1

Большинство «sluggifiers» (методы преобразования имен типа дружественного URL) имеют тенденцию делать следующее:

  1. Разделите все, кроме пробелов, тире, подчеркивания и буквенно-цифровых символов.
  2. (Необязательно) Удалите «общие слова» (a, a, an и т. д.).
  3. Заменить пробелы и символы подчеркивания тире.
  4. (Необязательно) Преобразование в нижний регистр.

Насколько я знаю, sluggifier StackOverflow делает # 1, # 3 и # 4, но не # 2.

    
ответ дан Amber 29.01.2010 в 12:55
  • Итак, мои замены выполняют те же самые: 1, 3 и 4. Мне просто пришлось добавить подчеркивание к первому шаблону reg ex. –  Robert Koritnik 29.01.2010 в 14:01
1

Как насчет этого:

string FriendlyURLTitle(string pTitle)
{
    pTitle = pTitle.Replace(" ", "-");
    pTitle = HttpUtility.UrlEncode(pTitle);
    return Regex.Replace(pTitle, "\%[0-9A-Fa-f]{2}", "");
}
    
ответ дан hannasm 29.01.2010 в 13:09
0

вот как я в настоящее время путаю слова.

        public static string Slug(this string value)
    {
        if (value.HasValue())
        {
            var builder = new StringBuilder();
            var slug = value.Trim().ToLowerInvariant();

            foreach (var c in slug)
            {
                switch (c)
                {
                    case ' ':
                        builder.Append("-");
                        break;
                    case '&':
                        builder.Append("and");
                        break;
                    default:

                        if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') && c != '-')
                        {
                            builder.Append(c);
                        }

                        break;
                }
            }

            return builder.ToString();
        }

        return string.Empty;
    }
    
ответ дан Mike Geise 29.01.2010 в 17:38
  • Извините, но я предпочитаю использовать регулярные выражения. Множество строк кода можно было бы с легкостью заменить двумя регулярными выражениями. –  Robert Koritnik 30.01.2010 в 16:43
  • ya, но по какой цене это будет вам, когда это регулярное выражение очень сложно и трудно понять. Я бы предпочел иметь поддерживаемость, а затем два загадочных регулярных выражения :) –  Mike Geise 30.01.2010 в 19:03
0

Я использую этот ...

    public static string ToUrlFriendlyString(this string value)
    {
        value = (value ?? "").Trim().ToLower();

        var url = new StringBuilder();

        foreach (char ch in value)
        {
            switch (ch)
            {
                case ' ':
                    url.Append('-');
                    break;
                default:
                    url.Append(Regex.Replace(ch.ToString(), @"[^A-Za-z0-9'()\*\+_~\:\/\?\-\.,;=#\[\]@!$&]", ""));
                    break;
            }
        }

        return url.ToString();
    }
    
ответ дан Keith Beller 20.04.2013 в 23:35
0

Это работает для меня

string output = Uri.UnescapeDataString(input);
    
ответ дан user4012980 28.09.2014 в 17:42