Stack Overflow, SEO dostu URL'lerini nasıl oluşturur?


253

İyi bir tam düzenli ifade veya başlığı alacak başka bir işlem nedir:

Bir başlığı, Yığın Taşması gibi URL'nin bir parçası olacak şekilde nasıl değiştirirsiniz?

ve dönüştür

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

taşması SEO dostu URL'lerde kullanılan nedir?

Kullandığım geliştirme ortamı Ruby on Rails , ancak platforma özgü başka çözümler (.NET, PHP, Django ) varsa, bunları da görmek isterim.

Eminim ben (ya da başka bir okuyucu) aynı problemle farklı bir platformda karşılaşacağım.

Ben özel yollar kullanıyorum ve ben esas olarak tüm özel karakterler kaldırılır dize değiştirmek için bilmek istiyorum, hepsi küçük harf, ve tüm boşluk değiştirilir.


Komik karakterler ne olacak? Bunlar hakkında ne yapacaksın? Sesli harfler? Noktalama? Bunların dikkate alınması gerekir. Temel olarak, yukarıdaki kara liste yaklaşımlarının aksine bir beyaz liste yaklaşımı kullanırdım: Hangi karakterlere izin vereceğinizi, hangi karakterlere dönüştüreceğinizi (neye?) Açıklayın ve geri kalanını anlamlı bir şeye değiştirin ("") . Bunu bir regex'te yapabileceğinizden şüpheliyim ... Neden sadece karakterler arasında dolaşmıyorsunuz?
Daren Thomas

1
Meta olarak taşınmalıdır ; soru ve cevap hem SO uygulaması ile özel olarak ilgilenir ve kabul edilen cevap @ JeffAtwood'dan gelir.
casperOne

19
@casperOne Sizce Jeff meta olmayan bir üne izin verilmiyor mu? Soru, "burada nasıl yapılır" değil, "böyle bir şeyi nasıl yapabilir" ile ilgilidir.
Paŭlo Ebermann

@ PaŭloEbermann: Bu Jeff meta olmayan bir üne kavuşmakla ilgili değil (ne kadar şöhreti gerçekten benim endişem değil); soru gövdesi StackOverflow'un uygulamasına özel olarak atıfta bulunur, dolayısıyla metada olmasının mantığı.
casperOne

Yanıtlar:


300

İşte böyle yapıyoruz. Muhtemelen ilk bakışta fark ettiğinden daha fazla kenar koşulunun olduğunu unutmayın.

Bu, 5 kat daha fazla performans için açılan ikinci versiyon (ve evet, karşılaştırdım). Optimize edeceğimi düşündüm çünkü bu işlev sayfa başına yüzlerce kez çağrılabilir.

/// <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();
}

Kodun değiştirilen önceki sürümünü görmek için (ancak işlevsel olarak eşdeğer ve 5 kat daha hızlıdır), bu yayının düzeltme geçmişini görüntüleyin (tarih bağlantısını tıklayın).

Ayrıca, RemapInternationalCharToAsciiyöntem kaynak kodu burada bulunabilir .


24
Sadece åäö gibi aksanlı karakterleri düşürmekle kalmaz, aynı zamanda onları aao'ya ayırır ... ^^
Oskar Duveborn

22
@oskar bu RemapInternationalCharToAscii()işlevin saplaması orada meta.stackexchange.com/questions/7435/…
Jeff Atwood

3
Bu harika. Şimdiye kadar yaptığım tek değişiklik "if (i == maxlen) break;" "if (sb.Length == maxlen) sonu;"
geçirdiğim

4
Küçük bir optimizasyon: if (prevdash) sb.Length -= 1; return sb.ToString();son ififade yerine .
Mark Hurd

8
@Dommer sb.Length == maxlen break;, maxLenght-1 üzerindeki işaret "ß" ise "ss" biçimine dönüştürülürse sb.Length == maxleneasla doğru olmayacaktır, bunun yerine test yapmak daha iyidir (sb.Length > = maxlen).
Henrik Stenbæk

32

İşte Jeff kodumun sürümü. Aşağıdaki değişiklikleri yaptım:

  • Tireler, eklenebilecek şekilde eklenmiştir ve daha sonra dizgideki son karakter olduğu için kaldırılması gerekir. Yani, asla “sümüklü böcek-” istemeyiz. Bu, bu kenar durumunda kaldırmak için fazladan bir dize ayırma anlamına gelir. Gecikme heceleyerek bu sorunu çözdüm. Kodumu Jeff'inkiyle karşılaştırırsanız bunun mantığını takip etmek kolaydır.
  • Onun yaklaşımı tamamen arama tabanlıdır ve Stack Overflow üzerinde araştırma yaparken örneklerde bulduğum birçok karakteri kaçırdı. Buna karşı koymak için önce bir normalizasyon geçişi (Meta Yığın Taşması sorusunda belirtilen AKA harmanlaması , tam (profil) URL'den bırakılan ABD-ASCII olmayan karakterler ) ve sonra kabul edilebilir aralıklar dışındaki karakterleri yok sayıyorum. Bu çoğu zaman işe yarar ...
  • ... olmadığı zamanlar için de bir arama tablosu eklemek zorunda kaldım. Yukarıda belirtildiği gibi, bazı karakterler normalleştirildiğinde düşük bir ASCII değerine eşlenmez. Bunları bırakmak yerine, şüphesiz deliklerle dolu bir istisnalar listesi var, ama hiçbir şeyden daha iyi. Normalleştirme kodundan, Jon Hanna'nın Stack Overflow sorusundaki büyük gönderisinden ilham alındı . Bir dizgideki aksanları nasıl kaldırabilirim? .
  • Vaka dönüşümü artık isteğe bağlıdır.

    public static class Slug
    {
        public static string Create(bool toLower, params string[] values)
        {
            return Create(toLower, String.Join("-", values));
        }
    
        /// <summary>
        /// Creates a slug.
        /// References:
        /// http://www.unicode.org/reports/tr15/tr15-34.html
        /// /meta/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696
        /// /programming/25259/how-do-you-include-a-webpage-title-as-part-of-a-webpage-url/25486#25486
        /// /programming/3769457/how-can-i-remove-accents-on-a-string
        /// </summary>
        /// <param name="toLower"></param>
        /// <param name="normalised"></param>
        /// <returns></returns>
        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;
        }
    }

Daha fazla ayrıntı için, birim testleri ve neden bir açıklama Facebook 'ın URL şeması Yığın Taşması biraz daha akıllı, ben bir var blogumda bu genişletilmiş versiyonu .


4
+1 Bu harika Dan. Ayrıca blogunuza if (i == maxlen) break;, bunun if (sb.Length == maxlen) break;yerine, muhtemelen çok fazla boşluk / geçersiz karakter içeren bir dize geçirirseniz, yine de istenen uzunlukta bir bilgi alabilirsiniz; kitlesel olarak kesiyor (örneğin 80 boşlukla başladığınız durumu düşünün ...). Ve Jeff'in koduna karşı 10.000.000 yinelemenin kabaca bir ölçütü, kabaca aynı hız olduğunu gösterdi.
Tom Chantler

1
Teşekkürler, bloguma cevap verdi ve o ve yukarıda kodu düzeltildi. Ayrıca kodu karşılaştırdığınız için teşekkür ederiz. İlgilenenler için Jeff'le eşitti.
DanH

2
Slug.Create () ile ilgili bazı sorunlar var gibi görünüyor: ÆØÅ'nin büyük harfli sürümleri düzgün dönüştürülmüyor ÆØ a çevrilirken ÆØ dikkate alınmaz. Normalde “å” kelimesini “aa”, “ø” kelimesini “oe” ve “æ” ifadesini “ae” olarak değiştirirsiniz. İkinci (sb.Length == maxlen) sonu; maxLenght-1 üzerindeki işaret "ß" ise (sb.Length == maxlen) hiçbir zaman doğru olmazsa (sb.Length> = maxlen) test etmek daha iyidir. Rastgele bir pozisyonda kesip son “-“ kesmemeniz için bastırıldım. "
Henrik Stenbæk

@DanH Kodun javascript sürümüne sahip olmak harika olurdu.
Freshblood

16

URL'yi işleyecek denetleyiciye yönlendirmek için özel bir yol ayarlamak isteyeceksiniz . Ruby on Rails kullandığınız için, yönlendirme motorlarını kullanmaya giriş .

Ruby'de, zaten bildiğiniz gibi normal bir ifadeye ihtiyacınız olacak ve işte kullanmak için normal ifade şöyledir:

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

11

Bu JavaScript işlevini, slug'ların form üretimi için de kullanabilirsiniz (bu, Django'ya dayanır / kopyalanır ):

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
}

Biraz ekleyelim ya da consts eklemek harika olurdu, çünkü bu vanilya JS değil.
Aditya Anand

8

İyi bir ölçü için, WordPress'te bunu yapan PHP işlevi ... WordPress'in süslü bağlantılar kullanan daha popüler platformlardan biri olduğunu düşünüyorum.

    işlev sanitize_title_with_dashes ($ title) {
            $ title = strip_tags ($ title);
            // Kaçan sekizlileri koru.
            $ title = preg_replace ('|% ([a-fA-F0-9] [a-fA-F0-9]) |', '--- 1 $ -', $ başlık);
            // Bir sekizlinin parçası olmayan yüzde işaretlerini kaldırın.
            $ title = str_replace ('%', '', $ başlık);
            // Sekizlileri geri yükle.
            $ title = preg_replace ('| --- ([a-fA-F0-9] [a-fA-F0-9]) --- |', '% $ 1', $ başlık);
            $ title = remove_accents ($ title);
            if (looks_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); // varlıkları öldür
            $ title = preg_replace ('/ [^% a-z0-9 _-] /', '', $ başlık);
            $ title = preg_replace ('/ \ s + /', '-', $ başlık);
            $ title = preg_replace ('| - + |', '-', $ başlık);
            $ title = trim ($ title, '-');
            $ başlık;
    }

Bu işlev ve bazı destekleyici işlevler wp-include / formatting.php dosyasında bulunabilir.


6
Bu tam bir cevap değil. Sen gibi işlevleri eksik: remove_accents, seems_utf8...
Nikola Loncar

@ How-To Geek cevabını hala tamamlayabilir git clone git://core.git.wordpress.org/ve wp-includes/formatting.phpdosyayı bulabilirsin
mickro

5

Rails kenarını kullanıyorsanız, Inflector.parametrize'a güvenebilirsiniz - işte belgelerden örnek:

  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="https://stackoverflow.com/person/1-donald-e-knuth">Donald E. Knuth</a>

Ayrıca, Rails'in önceki sürümünde aksanlar (éphémère) gibi daha egzotik karakterlerle başa çıkmanız gerekiyorsa, PermalinkFu ve DiacriticsFu'nun bir karışımını kullanabilirsiniz :

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

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

5

Ruby on Rails aşina değilim, ama aşağıdaki (denenmemiş) PHP kodu. Yararlı bulursanız muhtemelen Ruby on Rails'e çok hızlı bir şekilde çevirebilirsiniz.

$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

Umarım bu yardımcı olur.


4

Ruby veya Rails hakkında fazla bir şeyim yok, ama Perl'de şunu yaparım:

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";

Kısa bir test yaptım ve işe yarıyor gibi görünüyor. Umarım bu Ruby'ye tercüme etmek nispeten kolaydır.


4

Dbo.UrlEncode'dan uyarlanmış T-SQL uygulaması :

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

4

Çok eski bir soru olduğunu biliyorum ama tarayıcıların çoğu artık unicode url'leri desteklediğinden XRegex'te harfler hariç her şeyi dönüştüren harika bir çözüm buldum (tüm dillerde '-').

Bu, çeşitli programlama dillerinde yapılabilir.

Desen \\p{^L}+ve daha sonra tüm harfleri '-' yerine değiştirmek için kullanmanız yeterlidir.

Xregex modülü ile node.js'de çalışma örneği .

var text = 'This ! can @ have # several $ letters % from different languages such as עברית or Español';

var slugRegEx = XRegExp('((?!\\d)\\p{^L})+', 'g');

var slug = XRegExp.replace(text, slugRegEx, '-').toLowerCase();

console.log(slug) ==> "this-can-have-several-letters-from-different-languages-such-as-עברית-or-español"

3

Model sınıfınızın bir başlık niteliği olduğunu varsayarsak, model içindeki to_param yöntemini şu şekilde geçersiz kılabilirsiniz:

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

Bu Railscast bölümünün tüm detayları var. Ayrıca başlığın yalnızca geçerli karakterleri içerdiğinden emin olabilirsiniz:

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

2

Brian'ın kodu Ruby'de:

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

downcasedizeyi küçük harfe çevirir, stripöndeki ve sondaki boşlukları kaldırır, ilk gsubçağrı g lobally alt çizgilerle boşlukları keser ve ikincisi harf veya tire olmayan her şeyi kaldırır.


2

Bunu yapan PermalinkFu adlı küçük bir Ruby on Rails eklentisi var . Kaçış yöntemi bir için uygun bir dize dönüşümü yapar URL'ye . Koda bir göz atın; bu yöntem oldukça basit.

ASCII olmayan karakterleri kaldırmak için 'utf-8'den' ascii // ignore // translit 'e çevirmek için iconv lib kullanır. Daha sonra boşluklar tire işareti haline getirilir, her şey mahrum bırakılır, vb.


Bu mükemmel çalışıyor olsa da, bir şekilde çok verimli olmadığını hissediyorum.
WhyNotHugo

2

Aşağıdaki yardımcı yöntemi kullanabilirsiniz. Unicode karakterleri dönüştürebilir.

public static string ConvertTextToSlug(string s)
{
    StringBuilder sb = new StringBuilder();

    bool wasHyphen = true;

    foreach (char c in s)
    {
        if (char.IsLetterOrDigit(c))
        {
            sb.Append(char.ToLower(c));
            wasHyphen = false;
        }
        else
            if (char.IsWhiteSpace(c) && !wasHyphen)
            {
                sb.Append('-');
                wasHyphen = true;
            }
    }

    // Avoid trailing hyphens
    if (wasHyphen && sb.Length > 0)
        sb.Length--;

    return sb.ToString().Replace("--","-");
}

2

İşte Jeff kodunun (daha yavaş ama yazması eğlenceli) sürümü:

public static string URLFriendly(string title)
{
    char? prevRead = null,
        prevWritten = null;

    var seq = 
        from c in title
        let norm = RemapInternationalCharToAscii(char.ToLowerInvariant(c).ToString())[0]
        let keep = char.IsLetterOrDigit(norm)
        where prevRead.HasValue || keep
        let replaced = keep ? norm
            :  prevWritten != '-' ? '-'
            :  (char?)null
        where replaced != null
        let s = replaced + (prevRead == null ? ""
            : norm == '#' && "cf".Contains(prevRead.Value) ? "sharp"
            : norm == '+' ? "plus"
            : "")
        let _ = prevRead = norm
        from written in s
        let __ = prevWritten = written
        select written;

    const int maxlen = 80;  
    return string.Concat(seq.Take(maxlen)).TrimEnd('-');
}

public static string RemapInternationalCharToAscii(string text)
{
    var seq = text.Normalize(NormalizationForm.FormD)
        .Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark);

    return string.Concat(seq).Normalize(NormalizationForm.FormC);
}

Test dizem:

" I love C#, F#, C++, and... Crème brûlée!!! They see me codin'... they hatin'... tryin' to catch me codin' dirty... "


2

Stackoverflow çözüm harika ama modern tarayıcı (her zamanki gibi IE hariç) artık güzel utf8 kodlama işlemek:

resim açıklamasını buraya girin

Bu yüzden önerilen çözümü geliştirdim:

public static string ToFriendlyUrl(string title, bool useUTF8Encoding = false)
{
    ...

        else if (c >= 128)
        {
            int prevlen = sb.Length;
            if (useUTF8Encoding )
            {
                sb.Append(HttpUtility.UrlEncode(c.ToString(CultureInfo.InvariantCulture),Encoding.UTF8));
            }
            else
            {
                sb.Append(RemapInternationalCharToAscii(c));
            }
    ...
}

Pastebin Tam Kodu

Düzenleme: İşte kod için RemapInternationalCharToAscii(pastebin eksik olan) yöntemiyle.


Wikipedia'ya göre Mozilla 1.4, Netscape 7.1, Opera 7.11 IDNA'yı destekleyen ilk uygulamalar arasındaydı. Internet Explorer 6 için IDN desteği sağlamak üzere bir tarayıcı eklentisi bulunmaktadır. Internet Explorer 7.0 ve Windows Vista'nın URL API'leri IDN için yerel destek sağlar. UTF-8 karakterlerini kaldırmak gibi bir zaman kaybı. Yaşasın UTF-8 !!!
Muhammad Rehan Saeed

1

Ben düzenli ifadeler kullanmadan yapılan yolu sevdim, bu yüzden PHP taşındı. is_betweenKarakterleri kontrol etmek için bir fonksiyon ekledim :

function is_between($val, $min, $max)
{
    $val = (int) $val; $min = (int) $min; $max = (int) $max;

    return ($val >= $min && $val <= $max);
}

function international_char_to_ascii($char)
{
    if (mb_strpos('àåáâäãåa', $char) !== false)
    {
        return 'a';
    }

    if (mb_strpos('èéêëe', $char) !== false)
    {
        return 'e';
    }

    if (mb_strpos('ìíîïi', $char) !== false)
    {
        return 'i';
    }

    if (mb_strpos('òóôõö', $char) !== false)
    {
        return 'o';
    }

    if (mb_strpos('ùúûüuu', $char) !== false)
    {
        return 'u';
    }

    if (mb_strpos('çccc', $char) !== false)
    {
        return 'c';
    }

    if (mb_strpos('zzž', $char) !== false)
    {
        return 'z';
    }

    if (mb_strpos('ssšs', $char) !== false)
    {
        return 's';
    }

    if (mb_strpos('ñn', $char) !== false)
    {
        return 'n';
    }

    if (mb_strpos('ýÿ', $char) !== false)
    {
        return 'y';
    }

    if (mb_strpos('gg', $char) !== false)
    {
        return 'g';
    }

    if (mb_strpos('r', $char) !== false)
    {
        return 'r';
    }

    if (mb_strpos('l', $char) !== false)
    {
        return 'l';
    }

    if (mb_strpos('d', $char) !== false)
    {
        return 'd';
    }

    if (mb_strpos('ß', $char) !== false)
    {
        return 'ss';
    }

    if (mb_strpos('Þ', $char) !== false)
    {
        return 'th';
    }

    if (mb_strpos('h', $char) !== false)
    {
        return 'h';
    }

    if (mb_strpos('j', $char) !== false)
    {
        return 'j';
    }
    return '';
}

function url_friendly_title($url_title)
{
    if (empty($url_title))
    {
        return '';
    }

    $url_title = mb_strtolower($url_title);

    $url_title_max_length   = 80;
    $url_title_length       = mb_strlen($url_title);
    $url_title_friendly     = '';
    $url_title_dash_added   = false;
    $url_title_char = '';

    for ($i = 0; $i < $url_title_length; $i++)
    {
        $url_title_char     = mb_substr($url_title, $i, 1);

        if (strlen($url_title_char) == 2)
        {
            $url_title_ascii    = ord($url_title_char[0]) * 256 + ord($url_title_char[1]) . "\r\n";
        }
        else
        {
            $url_title_ascii    = ord($url_title_char);
        }

        if (is_between($url_title_ascii, 97, 122) || is_between($url_title_ascii, 48, 57))
        {
            $url_title_friendly .= $url_title_char;

            $url_title_dash_added = false;
        }
        elseif(is_between($url_title_ascii, 65, 90))
        {
            $url_title_friendly .= chr(($url_title_ascii | 32));

            $url_title_dash_added = false;
        }
        elseif($url_title_ascii == 32 || $url_title_ascii == 44 || $url_title_ascii == 46 || $url_title_ascii == 47 || $url_title_ascii == 92 || $url_title_ascii == 45 || $url_title_ascii == 47 || $url_title_ascii == 95 || $url_title_ascii == 61)
        {
            if (!$url_title_dash_added && mb_strlen($url_title_friendly) > 0)
            {
                $url_title_friendly .= chr(45);

                $url_title_dash_added = true;
            }
        }
        else if ($url_title_ascii >= 128)
        {
            $url_title_previous_length = mb_strlen($url_title_friendly);

            $url_title_friendly .= international_char_to_ascii($url_title_char);

            if ($url_title_previous_length != mb_strlen($url_title_friendly))
            {
                $url_title_dash_added = false;
            }
        }

        if ($i == $url_title_max_length)
        {
            break;
        }
    }

    if ($url_title_dash_added)
    {
        return mb_substr($url_title_friendly, 0, -1);
    }
    else
    {
        return $url_title_friendly;
    }
}


1

Kodu TypeScript'e taşıdım. JavaScript'e kolayca uyarlanabilir.

Prototipe bir .containsyöntem ekliyorum String, en son tarayıcıları veya ES6'yı hedefliyorsanız .includesbunun yerine kullanabilirsiniz .

if (!String.prototype.contains) {
    String.prototype.contains = function (check) {
        return this.indexOf(check, 0) !== -1;
    };
}

declare interface String {
    contains(check: string): boolean;
}

export function MakeUrlFriendly(title: string) {
            if (title == null || title == '')
                return '';

            const maxlen = 80;
            let len = title.length;
            let prevdash = false;
            let result = '';
            let c: string;
            let cc: number;
            let remapInternationalCharToAscii = function (c: string) {
                let s = c.toLowerCase();
                if ("àåáâäãåą".contains(s)) {
                    return "a";
                }
                else if ("èéêëę".contains(s)) {
                    return "e";
                }
                else if ("ìíîïı".contains(s)) {
                    return "i";
                }
                else if ("òóôõöøőð".contains(s)) {
                    return "o";
                }
                else if ("ùúûüŭů".contains(s)) {
                    return "u";
                }
                else if ("çćčĉ".contains(s)) {
                    return "c";
                }
                else if ("żźž".contains(s)) {
                    return "z";
                }
                else if ("śşšŝ".contains(s)) {
                    return "s";
                }
                else if ("ñń".contains(s)) {
                    return "n";
                }
                else if ("ýÿ".contains(s)) {
                    return "y";
                }
                else if ("ğĝ".contains(s)) {
                    return "g";
                }
                else if (c == 'ř') {
                    return "r";
                }
                else if (c == 'ł') {
                    return "l";
                }
                else if (c == 'đ') {
                    return "d";
                }
                else if (c == 'ß') {
                    return "ss";
                }
                else if (c == 'Þ') {
                    return "th";
                }
                else if (c == 'ĥ') {
                    return "h";
                }
                else if (c == 'ĵ') {
                    return "j";
                }
                else {
                    return "";
                }
            };

            for (let i = 0; i < len; i++) {
                c = title[i];
                cc = c.charCodeAt(0);

                if ((cc >= 97 /* a */ && cc <= 122 /* z */) || (cc >= 48 /* 0 */ && cc <= 57 /* 9 */)) {
                    result += c;
                    prevdash = false;
                }
                else if ((cc >= 65 && cc <= 90 /* A - Z */)) {
                    result += c.toLowerCase();
                    prevdash = false;
                }
                else if (c == ' ' || c == ',' || c == '.' || c == '/' || c == '\\' || c == '-' || c == '_' || c == '=') {
                    if (!prevdash && result.length > 0) {
                        result += '-';
                        prevdash = true;
                    }
                }
                else if (cc >= 128) {
                    let prevlen = result.length;
                    result += remapInternationalCharToAscii(c);
                    if (prevlen != result.length) prevdash = false;
                }
                if (i == maxlen) break;
            }

            if (prevdash)
                return result.substring(0, result.length - 1);
            else
                return result;
        }

0

Hayır hayır hayır. Hepiniz çok yanılıyorsunuz. Aksan-fu şeyler dışında, oraya gidiyorsunuz, ama Asya karakterleri hakkında ( nihonjin kardeşlerini düşünmedikleri için Ruby geliştiricilerine utanç ).

Firefox ve Safari'nin her ikisi de URL'de ASCII olmayan karakterler görüntüler ve açıkçası harika görünürler. ' Http://somewhere.com/news/read/ お 前 た ち は ア ホ ゃ な い か い ' gibi bağlantıları desteklemek güzel .

İşte bunu yapacak bazı PHP kodu, ama ben sadece yazdım ve stres test etmedim.

<?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;
    }

Misal:

$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);

Çıkışlar: コ リ ン -ve- ト ー マ ス -ve- ア ー ノ ル ド

'-Ve-', '' ve 'olarak değiştirilir.


4
Bu bilgi hakkında ne söyleyeceğimi gerçekten bilmiyorum.
sjas

3
Bu, bir switch case deyiminin ne zaman KULLANILMAMASINA gerçekten iyi bir örnek.
NickG
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.