[regex] 스택 오버플로는 SEO 친화적 인 URL을 어떻게 생성합니까?

좋은 정규 표현식 이나 제목을 취하는 다른 프로세스 는 무엇입니까?

스택 오버플로와 같은 URL의 일부로 제목을 어떻게 변경합니까?

그것을

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

스택 오버플로의 SEO 친화적 인 URL에 사용됩니까?

내가 사용하는 개발 환경은 Ruby on Rails 이지만 다른 플랫폼 별 솔루션 (.NET, PHP, Django ) 이 있다면 그 역시보고 싶습니다.

나는 (또는 다른 독자) 다른 플랫폼에서 같은 문제를 겪을 것이라고 확신합니다.

사용자 지정 경로를 사용하고 있으며 주로 모든 특수 문자가 제거되고 모두 소문자이며 모든 공백이 바뀌도록 문자열을 변경하는 방법을 알고 싶습니다.



답변

우리가하는 방법은 다음과 같습니다. 언뜻보기에 알고있는 것보다 더 많은 엣지 조건이있을 수 있습니다.

이것은 두 번째 버전으로 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의 코드와 비교하면 논리가 따르기 쉽습니다.
  • 그의 접근 방식은 순전히 조회 기반이며 스택 오버플로를 연구하는 동안 예제에서 찾은 많은 문자를 놓쳤습니다. 이 문제를 해결하기 위해 먼저 정규화 패스 (Meta Stack Overflow 질문 비 US-ASCII 문자가 전체 (프로필) URL에서 삭제됨)에 언급 된 AKA 데이터 정렬)를 수행 한 다음 허용 가능한 범위를 벗어난 문자는 무시합니다. 이것은 대부분의 시간에 작동합니다 …
  • … 그렇지 않은 경우 조회 테이블을 추가해야했습니다. 위에서 언급했듯이 일부 문자는 정규화 할 때 낮은 ASCII 값으로 매핑되지 않습니다. 이것을 삭제하는 대신 구멍이 가득한 예외 목록을 수동으로 얻었지만 아무것도 아닌 것보다 낫습니다. 정규화 코드는 스택 오버플로 질문에서 Jon Hanna의 위대한 게시물에서 영감을 얻었습니다 . 문자열에서 악센트를 제거하는 방법은 무엇입니까? .
  • 사례 변환도 이제 선택 사항입니다.

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

자세한 내용, 단위 테스트 및 FacebookURL 체계가 스택 오버플로보다 조금 더 똑똑한 이유에 대한 설명을 보려면 블로그에서이 버전을 확장했습니다 .


답변

URL 을 처리 할 컨트롤러로 URL 을 가리 키도록 사용자 지정 경로를 설정하려고 합니다. Ruby on Rails를 사용하고 있으므로 라우팅 엔진 사용에 대한 소개 입니다.

Ruby에서는 이미 알고있는 정규식이 필요하며 사용할 정규식은 다음과 같습니다.

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


답변

JavaScript 함수를 사용 하여 슬러그의 정보를 생성 할 수 있습니다 (이것은 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
}


답변

좋은 측정을 위해 여기에 WordPress의 PHP 기능이 있습니다 … WordPress는 멋진 링크를 사용하는 가장 인기있는 플랫폼 중 하나라고 생각합니다.

    sanitize_title_with_dashes ($ title) {
            $ title = strip_tags ($ 제목);
            // 이스케이프 된 옥텟을 유지합니다.
            $ title = preg_replace ( '| % ([a-fA-F0-9] [a-fA-F0-9]) |', '--- $ 1 ---', $ title);
            // 8 진수의 일부가 아닌 퍼센트 부호를 제거합니다.
            $ title = str_replace ( '%', '', $ title);
            // 옥텟을 복원합니다.
            $ 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 ($ 제목, 'UTF-8');
                    }
                    $ title = utf8_uri_encode ($ title, 200);
            }
            $ title = strtolower ($ 제목);
            $ title = preg_replace ( '/&.+?;/', '', $ title); // 엔티티 죽이기
            $ title = preg_replace ( '/ [^ % a-z0-9 _-] /', '', $ title);
            $ title = preg_replace ( '/ \ s + /', '-', $ title);
            $ title = preg_replace ( '|-+ |', '-', $ title);
            $ title = trim ($ title, '-');
            $ title를 반환;
    }

이 기능과 일부 지원 기능은 wp-includes / formatting.php에서 찾을 수 있습니다.


답변

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

당신은 레일의 이전 버전에서 악센트 (éphémère)로 이국적인 문자를 처리 할 필요 또한, 당신은 혼합 사용할 수 있습니다 PermalinkFuDiacriticsFu를 :

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

이게 도움이 되길 바란다.