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

时间:2020-03-05 18:42:38  来源:igfitidea点击:

什么是一个好的完整正则表达式或者其他带有标题的过程:

How do you change a title to be part of the URL like Stack Overflow?

然后变成

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

在StackOverflow上的SEO友好URL中使用的是什么?

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

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

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

解决方案

回答

我们将需要设置一个自定义路由,以将URL指向将处理该URL的控制器。由于我们使用的是Ruby on Rails,因此这里是使用其路由引擎的介绍。

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

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

回答

我不熟悉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

我希望这有帮助。

回答

我对Ruby或者Rails的了解不多,但是在Perl中,我会这样做:

my $title = "How do you change a title to be part of the url like Stackoverflow?";

my $url = lc $title;   # Change to lower case and copy to URL.
$url =~ s/^\s+//g;     # Remove leading spaces.
$url =~ s/\s+$//g;     # Remove trailing spaces.
$url =~ s/\s+/\-/g;    # Change one or more spaces to single hyphen.
$url =~ s/[^\w\-]//g;  # Remove any non-word characters.

print "$title\n$url\n";

我只是做了一个快速测试,它似乎可以工作。希望这相对容易翻译成Ruby。

回答

假设模型类具有title属性,则可以简单地覆盖模型中的to_param方法,如下所示:

def to_param
  title.downcase.gsub(/ /, '-')
end

这个Railscast插曲包含所有详细信息。我们还可以使用以下方法确保标题仅包含有效字符:

validates_format_of :title, :with => /^[a-z0-9-]+$/,
                    :message => 'can only contain letters, numbers and hyphens'

回答

那有趣的角色呢?你打算怎么办?乌姆劳人?标点?这些需要考虑。基本上,我将使用白名单方法,而不是上面的黑名单方法:描述我们将允许哪些字符,将哪些字符转换(转换为什么?),然后将其余字符更改为有意义的东西("") 。我怀疑我们是否可以在一个正则表达式中执行此操作?为什么不仅仅遍历字符?

回答

Brian的Ruby代码:

title.downcase.strip.gsub(/\ /, '-').gsub(/[^\w\-]/, '')

downcase将字符串转换为小写字母,strip除去前导和尾随的空格,第一个gsub调用全局地用破折号代替空格,第二个`gsub'除去所有不是字母或者破折号的东西。

回答

这是我们的方法。请注意,边缘条件可能比我们乍看之下要多。

这是第二个版本,已推出,性能提高了5倍(是的,我对其进行了基准测试)。我认为我会对其进行优化,因为该功能每页可以被调用数百次。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

/// <summary>
/// Produces optional, URL-friendly version of a title, "like-this-one". 
/// hand-tuned for speed, reflects performance refactoring contributed
/// by John Gietzen (user otac0n) 
/// </summary>
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方法的源代码。

回答

从好的方面来说,这是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])|', '------', $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])---|', '%', $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中找到。

回答

有一个名为PermalinkFu的小型Ruby on Rails插件可以做到这一点。转义方法将转换为适合URL的字符串。看一下代码;该方法非常简单。

要删除非ASCII字符,它使用iconv库将其从'utf-8'转换为'ascii // ignore // translit'。然后将空格变成破折号,将所有内容缩小写,等等。

回答

我们还可以使用此JavaScript函数以形式形式生成子弹(该子弹基于Django /从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
}

回答

T-SQL实现,改编自dbo.UrlEncode:

CREATE FUNCTION dbo.Slug(@string varchar(1024))
RETURNS varchar(3072)
AS
BEGIN
    DECLARE @count int, @c char(1), @i int, @slug varchar(3072)

    SET @string = replace(lower(ltrim(rtrim(@string))),' ','-')

    SET @count = Len(@string)
    SET @i = 1
    SET @slug = ''

    WHILE (@i <= @count)
    BEGIN
        SET @c = substring(@string, @i, 1)

        IF @c LIKE '[a-z0-9--]'
            SET @slug = @slug + @c

        SET @i = @i +1
    END

    RETURN @slug
END

回答

如果我们使用的是Rails edge,则可以依赖Inflector.parametrize,这是文档中的示例:

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

  @person = Person.find(1)
  # => #<Person id: 1, name: "Donald E. Knuth">

  <%= link_to(@person.name, person_path(@person)) %>
  # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>

另外,如果我们需要在早期版本的Rails中处理更多的异国字符,例如重音符号(phmre),则可以混合使用PermalinkFu和DiacriticsFu:

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

DiacriticsFu::escape("r?ksm?rg?s")
=> "raksmorgas"

回答

不不不。你们都非常错。除了变音符之类的东西外,我们到那里去了,但是亚洲字符呢(Ruby开发人员因为不考虑他们的nihonjin弟兄而感到羞耻)。

Firefox和Safari都在URL中显示非ASCII字符,坦率地说,它们看起来很棒。很高兴支持" http://somewhere.com/news/read/"之类的链接。

因此,这里有一些PHP代码可以做到这一点,但是我只是编写了它,并且没有对其进行压力测试。

<?php
    function slug($str)
    {
        $args = func_get_args();
        array_filter($args);  //remove blanks
        $slug = mb_strtolower(implode('-', $args));

        $real_slug = '';
        $hyphen = '';
        foreach(SU::mb_str_split($slug) as $c)
        {
            if (strlen($c) > 1 && mb_strlen($c)===1)
            {
                $real_slug .= $hyphen . $c;
                $hyphen = '';
            }
            else
            {
                switch($c)
                {
                    case '&':
                        $hyphen = $real_slug ? '-and-' : '';
                        break;
                    case 'a':
                    case 'b':
                    case 'c':
                    case 'd':
                    case 'e':
                    case 'f':
                    case 'g':
                    case 'h':
                    case 'i':
                    case 'j':
                    case 'k':
                    case 'l':
                    case 'm':
                    case 'n':
                    case 'o':
                    case 'p':
                    case 'q':
                    case 'r':
                    case 's':
                    case 't':
                    case 'u':
                    case 'v':
                    case 'w':
                    case 'x':
                    case 'y':
                    case 'z':

                    case 'A':
                    case 'B':
                    case 'C':
                    case 'D':
                    case 'E':
                    case 'F':
                    case 'G':
                    case 'H':
                    case 'I':
                    case 'J':
                    case 'K':
                    case 'L':
                    case 'M':
                    case 'N':
                    case 'O':
                    case 'P':
                    case 'Q':
                    case 'R':
                    case 'S':
                    case 'T':
                    case 'U':
                    case 'V':
                    case 'W':
                    case 'X':
                    case 'Y':
                    case 'Z':

                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        $real_slug .= $hyphen . $c;
                        $hyphen = '';
                        break;

                    default:
                       $hyphen = $hyphen ? $hyphen : ($real_slug ? '-' : '');
                }
            }
        }
        return $real_slug;
    }

例子:

$str = "~!@#$%^&*()_+-=[]\{}|;':\",./<>?\n\r\t\x07\x00\x04 コリン ~!@#$%^&*()_+-=[]\{}|;':\",./<>?\n\r\t\x07\x00\x04 トーマス ~!@#$%^&*()_+-=[]\{}|;':\",./<>?\n\r\t\x07\x00\x04 アーノルド ~!@#$%^&*()_+-=[]\{}|;':\",./<>?\n\r\t\x07\x00\x04";
echo slug($str);

输出:
-和-和-

"与"是因为&更改为"与"。