كيف يقوم Stack Overflow بإنشاء عناوين URL صديقة لكبار المسئولين الاقتصاديين (SEO)؟

StackOverflow https://stackoverflow.com/questions/25259

سؤال

ما هو جيد كاملا تعبير عادي أو بعض العمليات الأخرى التي قد تأخذ العنوان:

كيف يمكنك تغيير العنوان ليكون جزءًا من عنوان URL مثل Stack Overflow؟

وتحويلها الى

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

المستخدمة في عناوين URL الملائمة لتحسين محركات البحث في Stack Overflow؟

بيئة التطوير التي أستخدمها هي روبي على القضبان, ، ولكن إذا كانت هناك بعض الحلول الأخرى الخاصة بالنظام الأساسي (.NET، PHP، جانغو)، وأنا أحب أن أرى تلك أيضا.

أنا متأكد من أنني (أو أي قارئ آخر) سوف أواجه نفس المشكلة على منصة مختلفة في المستقبل.

أنا أستخدم مسارات مخصصة، وأريد بشكل أساسي معرفة كيفية تغيير السلسلة بحيث تتم إزالة كافة الأحرف الخاصة، وكلها صغيرة، ويتم استبدال كل المسافات البيضاء.

هل كانت مفيدة؟

المحلول

وإليك كيف نفعل ذلك.لاحظ أنه من المحتمل أن تكون هناك شروط حافة أكثر مما تدرك للوهلة الأولى.

هذا هو الإصدار الثاني، الذي تم نشره للحصول على أداء أفضل بمقدار 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 يمكن العثور على كود مصدر الطريقة هنا.

نصائح أخرى

هذه هي نسختي من كود جيف.لقد قمت بإجراء التغييرات التالية:

  • تم إلحاق الواصلات بطريقة يمكن إضافة واحدة منها، ثم تحتاج إلى إزالتها لأنها كانت الحرف الأخير في السلسلة.وهذا يعني أننا لا نريد أبدًا "my-slug-".وهذا يعني تخصيص سلسلة إضافية لإزالتها من حالة الحافة هذه.لقد تعاملت مع هذا عن طريق الواصلة المؤجلة.إذا قارنت الكود الخاص بي بكود Jeff، فمن السهل اتباع المنطق الخاص بذلك.
  • يعتمد منهجه على البحث تمامًا ويفتقد الكثير من الشخصيات التي وجدتها في الأمثلة أثناء البحث عن Stack Overflow.لمواجهة ذلك، أقوم أولاً بإجراء تمريرة تسوية (تم ذكر تجميع AKA في سؤال Meta Stack Overflow تم إسقاط أحرف غير US-ASCII من عنوان URL الكامل (الملف الشخصي).)، ثم تجاهل أية أحرف خارج النطاقات المقبولة.هذا يعمل اغلب الاوقات...
  • ...لأنه عندما لا يكون الأمر كذلك، كان عليّ أيضًا إضافة جدول بحث.كما ذكرنا سابقًا، لا يتم تعيين بعض الأحرف إلى قيمة ASCII منخفضة عند تطبيعها.بدلاً من إسقاط هذه الاستثناءات، لدي قائمة يدوية بالاستثناءات التي لا شك أنها مليئة بالثغرات، ولكنها أفضل من لا شيء.رمز التطبيع مستوحى من مشاركة جون هانا الرائعة في سؤال Stack Overflow كيف يمكنني إزالة لهجات على سلسلة؟.
  • أصبح تحويل الحالة الآن اختياريًا أيضًا.

    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
        /// https://meta.stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696
        /// https://stackoverflow.com/questions/25259/how-do-you-include-a-webpage-title-as-part-of-a-webpage-url/25486#25486
        /// https://stackoverflow.com/questions/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;
        }
    }
    

ولمزيد من التفاصيل اختبارات الوحدة وشرح السبب فيسبوكعنوان URL المخطط أكثر ذكاءً قليلاً من Stack Overflows، لقد حصلت على نسخة موسعة من هذا على مدونتي.

سوف ترغب في إعداد مسار مخصص للإشارة إلى عنوان URL إلى وحدة التحكم التي ستتعامل معها.نظرًا لأنك تستخدم Ruby on Rails، فإليك ملف مقدمة في استخدام محرك التوجيه الخاص بهم.

في روبي، ستحتاج إلى تعبير عادي كما تعرفه بالفعل، وإليك التعبير العادي الذي يجب استخدامه:

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

يمكنك أيضًا استخدام هذا جافا سكريبت وظيفة لإنشاء سبيكة في النموذج (يعتمد هذا على/منسوخ من جانغو):

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
}

لحسن التدبير، إليك وظيفة PHP في WordPress التي تقوم بذلك...أعتقد أن 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.

إذا كنت تستخدم Rails edge، فيمكنك الاعتماد عليه Inflector.parameterize - إليك المثال من الوثائق:

  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>

أيضًا، إذا كنت بحاجة إلى التعامل مع أحرف أكثر غرابة مثل اللكنات (éphémère) في الإصدار السابق من Rails، فيمكنك استخدام مزيج من الرابط الثابتFu و علامات التشكيلFu:

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

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

لست على دراية بـ 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";

لقد أجريت للتو اختبارًا سريعًا ويبدو أنه يعمل.نأمل أن يكون هذا سهلًا نسبيًا للترجمة إلى روبي.

تنفيذ 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

على افتراض أن فئة النموذج الخاص بك لديها سمة عنوان، يمكنك ببساطة تجاوز طريقة 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'

أعلم أنه سؤال قديم جدًا ولكن منذ أن أصبحت معظم المتصفحات الآن دعم عناوين URL يونيكود لقد وجدت حلا رائعا في XRegex الذي يحول كل شيء باستثناء الحروف (في جميع اللغات إلى "-").

ويمكن القيام بذلك بعدة لغات برمجة.

النمط هو \\p{^L}+ وبعد ذلك تحتاج فقط إلى استخدامه لاستبدال جميع الأحرف غير الأحرف إلى "-".

مثال عملي في Node.js مع com.xregex وحدة.

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"

كود بريان في روبي:

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

downcase تحويل السلسلة إلى أحرف صغيرة، strip يزيل المسافة البيضاء البادئة والزائدة، الأولى gsub يتصل زمحليا الفرعيةينشئ مسافات بشرطات، والثاني يزيل كل ما ليس حرفًا أو شرطة.

هناك مكون إضافي صغير لـ Ruby on Rails يسمى الرابط الثابتFu, ، يفعل هذا.ال طريقة الهروب يقوم بالتحويل إلى سلسلة مناسبة لـ a عنوان URL.ألق نظرة على الكود؛هذه الطريقة بسيطة للغاية.

لإزالة غيرأسكي يستخدم Iconv lib للترجمة إلى "ascii//ignore//translit" من "utf-8".يتم بعد ذلك تحويل المسافات إلى شرطات، ويتم تصغير كل شيء، وما إلى ذلك.

يمكنك استخدام طريقة المساعد التالية.يمكنه تحويل أحرف Unicode.

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

إليك الإصدار (الأبطأ ولكن الممتع في الكتابة) من كود جيف:

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

سلسلة الاختبار الخاصة بي:

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

ال حل تدفق المكدس رائع، لكن المتصفح الحديث (باستثناء IE، كالعادة) يتعامل الآن بشكل جيد مع ترميز utf8:

enter image description here

لذلك قمت بترقية الحل المقترح:

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

يحرر: هذا هو الرمز ل RemapInternationalCharToAscii الطريقة (التي مفقودة في سلة المهملات).

أعجبتني الطريقة التي يتم بها ذلك دون استخدام التعبيرات العادية, ، لذلك قمت بنقله إلى PHP.لقد أضفت للتو وظيفة تسمى is_between للتحقق من الأحرف:

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

الآن تتعامل جميع المتصفحات بشكل جيد مع ترميز utf8، حتى تتمكن من استخدامه WebUtility.UrlEncode الطريقة، مثلها HttpUtility.UrlEncode يستخدمه @giamin ولكنه يعمل خارج تطبيق الويب.

لا لا لا.أنتم جميعا مخطئون جدا.باستثناء عناصر التشكيل، لقد وصلت إلى هناك، ولكن ماذا عن الشخصيات الآسيوية (عار على مطوري روبي لعدم أخذهم بعين الاعتبار com.nihonjin الاخوة).

يعرض كل من Firefox وSafari أحرفًا غير ASCII في ملف عنوان URL, وبصراحة تبدو رائعة.من الجيد دعم الروابط مثل "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);

النواتج:コリン-و-ト マ ス، و-

"-و-" لأنه تم تغيير & إلى "-و-".

لقد قمت بنقل الكود إلى TypeScript.ويمكن بسهولة أن تتكيف مع جافا سكريبت.

أقوم بإضافة أ .contains طريقة إلى String النموذج الأولي، إذا كنت تستهدف أحدث المتصفحات أو ES6 يمكنك استخدامها .includes بدلاً من.

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;
        }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top