当前位置:  开发笔记 > 编程语言 > 正文

Stack Overflow如何生成其SEO友好的URL?

如何解决《StackOverflow如何生成其SEO友好的URL?》经验,为你挑选了7个好方法。

什么是完整的正则表达式或其他一些可以获得标题的过程:

如何将标题更改为Stack Overflow等URL的一部分?

把它变成

how-do-you-change-a-title-to-be-part-of-the-url-like-stack-overflow

Stack Overflow上的SEO友好URL中使用了哪些?

我使用的开发环境是Ruby on Rails,但是如果还有其他一些特定于平台的解决方案(.NET,PHP,Django),我也很乐意看到它们.

我相信我(或其他读者)会在不同的平台上遇到同样的问题.

我正在使用自定义路由,我主要想知道如何更改字符串以删除所有特殊字符,它全部小写,并且所有空格都被替换.



1> Jeff Atwood..:

这是我们如何做到的.请注意,乍看之下可能存在比边缘条件更多的边缘条件.

这是第二个版本,展开了5倍以上的性能(是的,我对它进行了基准测试).我想我会优化它,因为这个函数每页可以被调用数百次.

/// 
/// Produces optional, URL-friendly version of a title, "like-this-one". 
/// hand-tuned for speed, reflects performance refactoring contributed
/// by John Gietzen (user otac0n) 
/// 
public static string URLFriendly(string title)
{
    if (title == null) return "";

    const int maxlen = 80;
    int len = title.Length;
    bool prevdash = false;
    var sb = new StringBuilder(len);
    char c;

    for (int i = 0; i < len; i++)
    {
        c = title[i];
        if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
        {
            sb.Append(c);
            prevdash = false;
        }
        else if (c >= 'A' && c <= 'Z')
        {
            // tricky way to convert to lowercase
            sb.Append((char)(c | 32));
            prevdash = false;
        }
        else if (c == ' ' || c == ',' || c == '.' || c == '/' || 
            c == '\\' || c == '-' || c == '_' || c == '=')
        {
            if (!prevdash && sb.Length > 0)
            {
                sb.Append('-');
                prevdash = true;
            }
        }
        else if ((int)c >= 128)
        {
            int prevlen = sb.Length;
            sb.Append(RemapInternationalCharToAscii(c));
            if (prevlen != sb.Length) prevdash = false;
        }
        if (i == maxlen) break;
    }

    if (prevdash)
        return sb.ToString().Substring(0, sb.Length - 1);
    else
        return sb.ToString();
}

要查看此代码的先前版本(已在功能上等效,并且速度提高了5倍),请查看此帖子的修订历史记录(单击日期链接).

此外,RemapInternationalCharToAscii方法源代码可以在这里找到.


如果一个版本不仅像åäö那样丢弃重音字符,而是将它们分解为aao ......那就太好了...... ^^
@oskar那个`RemapInternationalCharToAscii()`函数的存根是http://meta.stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696
@Dommer`sb.Length == maxlen break;`如果maxLenght-1上的符号是"ß"它会被转换为"ss"sb.Length == maxlene`永远不会是真的,那么它是错误的,它更好地代替测试`(sb.Length> = maxlen)`.
一个小优化:`if(prevdash)sb.Length - = 1; return sb.ToString();`而不是最后一个`if`语句.
这很棒.到目前为止,我所做的唯一改变是改变"if(i == maxlen)break;" 成为"if(sb.Length == maxlen)休息;" 以防万一我传入的字符串中有大量无效字符.

2> DanH..:

这是我的杰夫代码版本.我做了以下更改:

连字符的附加方式可以添加一个,然后需要删除,因为它是字符串中的最后一个字符.也就是说,我们从不想要"my-slug-".这意味着额外的字符串分配将在此边缘情况下删除它.我通过推迟延迟来解决这个问题.如果你将我的代码与Jeff的代码进行比较,那么这个逻辑很容易理解.

他的方法纯粹基于查找,并且在研究Stack Overflow时错过了我在示例中找到的很多字符.为了解决这个问题,我首先执行一个规范化传递(在Meta Stack Overflow问题中提到的AKA校对,从完整(配置文件)URL中删除非US-ASCII字符),然后忽略可接受范围之外的任何字符.这大部分时间都有效......

...当它没有时,我也必须添加一个查找表.如上所述,某些字符在规范化时不会映射到低ASCII值.而不是删除这些,我有一个手动的异常列表,无疑是充满漏洞,但它总比没有好.标准化代码的灵感来自于Jon Hanna在Stack Overflow问题中的精彩帖子如何删除字符串上的重音?.

案例转换现在也是可选的.

public static class Slug
{
    public static string Create(bool toLower, params string[] values)
    {
        return Create(toLower, String.Join("-", values));
    }

    /// 
    /// Creates a slug.
    /// References:
    /// http://www.unicode.org/reports/tr15/tr15-34.html
    /// https://meta.stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696
    /// /sf/ask/17360801/#25486
    /// /sf/ask/17360801/
    /// 
    /// 
    /// 
    /// 
    public static string Create(bool toLower, string value)
    {
        if (value == null)
            return "";

        var normalised = value.Normalize(NormalizationForm.FormKD);

        const int maxlen = 80;
        int len = normalised.Length;
        bool prevDash = false;
        var sb = new StringBuilder(len);
        char c;

        for (int i = 0; i < len; i++)
        {
            c = normalised[i];
            if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
            {
                if (prevDash)
                {
                    sb.Append('-');
                    prevDash = false;
                }
                sb.Append(c);
            }
            else if (c >= 'A' && c <= 'Z')
            {
                if (prevDash)
                {
                    sb.Append('-');
                    prevDash = false;
                }
                // Tricky way to convert to lowercase
                if (toLower)
                    sb.Append((char)(c | 32));
                else
                    sb.Append(c);
            }
            else if (c == ' ' || c == ',' || c == '.' || c == '/' || c == '\\' || c == '-' || c == '_' || c == '=')
            {
                if (!prevDash && sb.Length > 0)
                {
                    prevDash = true;
                }
            }
            else
            {
                string swap = ConvertEdgeCases(c, toLower);

                if (swap != null)
                {
                    if (prevDash)
                    {
                        sb.Append('-');
                        prevDash = false;
                    }
                    sb.Append(swap);
                }
            }

            if (sb.Length == maxlen)
                break;
        }
        return sb.ToString();
    }

    static string ConvertEdgeCases(char c, bool toLower)
    {
        string swap = null;
        switch (c)
        {
            case '?':
                swap = "i";
                break;
            case '?':
                swap = "l";
                break;
            case '?':
                swap = toLower ? "l" : "L";
                break;
            case '?':
                swap = "d";
                break;
            case 'ß':
                swap = "ss";
                break;
            case 'ø':
                swap = "o";
                break;
            case 'Þ':
                swap = "th";
                break;
        }
        return swap;
    }
}

有关详细信息,单元测试,以及解释为什么Facebook的URL方案比Stack Overflows更聪明,我在我的博客上有一个扩展版本.


+1这是伟大的丹.我还在你的博客上添加了一条评论,关于可能改变`if(i == maxlen)break;`是`if(sb.Length == maxlen)break;`而不是如果你传入一个包含很多字符串的字符串空格/无效字符你仍然可以得到一个所需长度的slug,而它所代表的代码可能最终会大量截断它(例如考虑你从80个空格开始的情况......).对Jeff的代码进行10,000,000次迭代的粗略基准测试表明它的速度大致相同.
似乎Slug.Create()存在一些问题:ÆØÅ的大写版本未正确转换ÆØ被忽略而Å被转换为a.通常你会将"å"转换为"aa",将"ø"转换为"oe",将"æ"转换为"ae".第二个(sb.Length == maxlen)休息; 如果maxLenght-1上的符号是"ß"(sb.Length == maxlen)永远不会是真的,那么它是错误的,而不是测试(sb.Length> = maxlen).我被压制你切断了任何随机位置而不是最后一个" - ",这将使你最终避免以一个不想要的词结尾:好像你必须在最后一个之后切断"断言" "

3> Dale Ragan..:

您将需要设置自定义路由以将URL指向将处理它的控制器.由于您使用的是Ruby on Rails,因此以下是使用其路由引擎的介绍.

在Ruby中,您将需要一个您已经知道的正则表达式,这里是要使用的正则表达式:

def permalink_for(str)
    str.gsub(/[^\w\/]|[!\(\)\.]+/, ' ').strip.downcase.gsub(/\ +/, '-')
end



4> fijter..:

你也可以使用这个JavaScript函数来生成slug的形式(这个是基于/从Django复制的):

function makeSlug(urlString, filter) {
    // Changes, e.g., "Petty theft" to "petty_theft".
    // Remove all these words from the string before URLifying

    if(filter) {
        removelist = ["a", "an", "as", "at", "before", "but", "by", "for", "from",
        "is", "in", "into", "like", "of", "off", "on", "onto", "per",
        "since", "than", "the", "this", "that", "to", "up", "via", "het", "de", "een", "en",
        "with"];
    }
    else {
        removelist = [];
    }
    s = urlString;
    r = new RegExp('\\b(' + removelist.join('|') + ')\\b', 'gi');
    s = s.replace(r, '');
    s = s.replace(/[^-\w\s]/g, ''); // Remove unneeded characters
    s = s.replace(/^\s+|\s+$/g, ''); // Trim leading/trailing spaces
    s = s.replace(/[-\s]+/g, '-'); // Convert spaces to hyphens
    s = s.toLowerCase(); // Convert to lowercase
    return s; // Trim to first num_chars characters
}



5> The How-To G..:

为了更好的衡量,这里是WordPress中的PHP函数,它做到了......我认为WordPress是使用花哨链接的更受欢迎的平台之一.

    function sanitize_title_with_dashes($title) {
            $title = strip_tags($title);
            // Preserve escaped octets.
            $title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title);
            // Remove percent signs that are not part of an octet.
            $title = str_replace('%', '', $title);
            // Restore octets.
            $title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title);
            $title = remove_accents($title);
            if (seems_utf8($title)) {
                    if (function_exists('mb_strtolower')) {
                            $title = mb_strtolower($title, 'UTF-8');
                    }
                    $title = utf8_uri_encode($title, 200);
            }
            $title = strtolower($title);
            $title = preg_replace('/&.+?;/', '', $title); // kill entities
            $title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
            $title = preg_replace('/\s+/', '-', $title);
            $title = preg_replace('|-+|', '-', $title);
            $title = trim($title, '-');
            return $title;
    }

这个函数以及一些支持函数可以在wp-includes/formatting.php中找到.


这不是完整的答案.你缺少像`remove_accents`,`seem_utf8`这样的函数......

6> Vegard Larse..:

我不熟悉Ruby on Rails,但以下是(未经测试的)PHP代码.如果你觉得它很有用,你可以很快地将它翻译成Ruby on Rails.

$sURL = "This is a title to convert to URL-format. It has 1 number in it!";
// To lower-case
$sURL = strtolower($sURL);

// Replace all non-word characters with spaces
$sURL = preg_replace("/\W+/", " ", $sURL);

// Remove trailing spaces (so we won't end with a separator)
$sURL = trim($sURL);

// Replace spaces with separators (hyphens)
$sURL = str_replace(" ", "-", $sURL);

echo $sURL;
// outputs: this-is-a-title-to-convert-to-url-format-it-has-1-number-in-it

我希望这有帮助.



7> Thibaut Barr..:

如果您正在使用Rails边缘,您可以依赖Inflector.parametrize - 这是文档中的示例:

  class Person
    def to_param
      "#{id}-#{name.parameterize}"
    end
  end

  @person = Person.find(1)
  # => #

  <%= link_to(@person.name, person_path(@person)) %>
  # => Donald E. Knuth

此外,如果您需要在以前版本的Rails中处理更多异国情调的角色,例如口音(éphémère),您可以使用PermalinkFu和DiacriticsFu的混合:

DiacriticsFu::escape("éphémère")
=> "ephemere"

DiacriticsFu::escape("räksmörgås")
=> "raksmorgas"

推荐阅读
和谐啄木鸟
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有