2008-08-24 16 views
228

什么是一个很好的完整的regular expression或会拿冠军的一些其他工艺:Stack Overflow如何生成其适合搜索引擎优化的URL?

如何更改标题要像堆栈溢出的URL的一部分?

,并把它变成

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

是在堆栈溢出 的搜索引擎友好的URL中使用?

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

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

我正在使用自定义路由,而且我主要想知道如何更改字符串以删除所有特殊字符,这些都是小写字母,并且所有空白都被替换。

+1

应该迁移到[meta](http://meta.stackoverflow.com);因为问题和答案都具体处理SO实施,并且接受的答案来自@JeffAtwood。 – casperOne 2011-11-18 20:21:28

+19

@casperOne你认为杰夫不被允许一些非元的声誉?问题是关于“如何做这样的事情”,而不是“这里做得如何”。 – 2011-11-19 13:05:32

+0

@PaŭloEbermann:这不是关于杰夫获得一些非meta的声誉(他有多少声望真的不是我关心的);问题主体*特别引用了StackOverflow的实现*因此它的基本原理是meta。 – casperOne 2011-11-22 14:04:12

回答

266

下面是我们如何做到这一点。请注意,乍一看可能会有更多的边缘条件。

这是第二个版本,展开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方法的源代码可以找到here

+21

这样的版本不仅可以删除像åäö这样的重音字符,而可以将它们撤销到aao ... ^^ – 2009-11-16 20:48:06

+21

@oskar该`RemapInternationalCharToAscii()`函数的存根存在http:// meta。 stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696 – 2011-03-15 03:25:45

+3

这太好了。我迄今为止所做的唯一改变是改变“if(i == maxlen)break;”成为“if(sb.Length == maxlen)break”;以防万一在我传入的字符串中有很多无效字符。 – 2011-05-30 18:21:38

16

您将需要设置一个自定义路线,将URL指向将处理它的控制器。由于您使用的是Ruby on Rails,因此使用路由引擎时需要使用introduction

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

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

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

我希望这会有所帮助。

4

我没有太多关于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。

3

假设你的模型类有一个title属性,你可以简单地在模型中重写to_param方法,像这样:

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

This Railscast episode有所有的细节。您还可以确保标题仅包含使用此的有效字符:

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

有趣的角色呢?你打算怎么做呢?变音?标点?这些需要考虑。基本上,我会使用白名单的方法,而不是上面的黑名单方法:描述你将允许哪些字符,你将转换哪些字符(转换成什么?),然后将其余的字符转换为有意义的字符(“”) 。我怀疑你可以在一个正则表达式中做到这一点...为什么不循环遍历字符?

2

Brian的代码,在Ruby中:

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

downcase变成字符串为小写,strip除去开头和结尾的空白,第一gsub呼叫 lobally stitutes空间用破折号,而第二删除所有不是字母或短划线的内容。

9

对于好的措施,这里是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中找到。

2

有一个小的Ruby on Rails插件,名为PermalinkFu,这样做。 escape method将转换为适用于URL的字符串。看看代码;该方法非常简单。

要删除非ASCII个字符,它会使用iconv lib转换为'utf-8'中的'ascii // ignore // translit'。然后空间都变成破折号,一切都downcased等

11

您也可以使用此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 
} 
4

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 
5

如果您使用Rails的边缘,你可以依靠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的处理更奇特的字符,如重音符号(éphémère),你可以使用的PermalinkFuDiacriticsFu的混合物:

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

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

不,不,不。你们都很错误。除了音调符号之外,你会到达那里,但是亚洲人物怎么样(Ruby开发者因为没有考虑他们的弟兄而感到羞耻)。

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

输出: コリン - 和 - トーマス - 和 - アーノルド

的 ' - 和 - ' 是因为&的get改为“ - 和 - ”。

28

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

  • 连字符以这样的方式添加,即可以添加一个连字符,然后需要删除,因为它是字符串中的最后一个字符。也就是说,我们从不想要“my-slug-”。这意味着一个额外的字符串分配来删除它在这种边缘情况下。我通过延迟连字符解决了这个问题。如果您将我的代码与杰夫的代码进行比较,那么这很容易遵循。
  • 他的方法纯粹是基于查找的,并且在研究堆栈时错过了很多在示例中找到的字符 溢出。为了解决这个问题,我首先执行正常化过程(在堆栈溢出问题Non US-ASCII characters dropped from full (profile) URL中提到的AKA整理),然后忽略可接受范围以外的任何字符。这在大部分时间都适用...
  • ...因为当它没有时,我还必须添加一个查找表。如上所述,一些字符在归一化时不会映射到低ASCII值。与其放弃这些,我已经得到了一个毫无疑问充满漏洞的例外手册,但总比没有好。规范化代码的灵感来自Jon Hanna在堆栈溢出问题How can I remove accents on a string?的伟大职位。
  • 大小写转换现在也是可选的。

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

有关详细信息,单元测试,以及为什么FacebookURL方案比堆栈溢出聪明一点的解释,我有一个expanded version of this on my blog

2

您可以使用以下辅助方法。它可以转换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("--","-"); 
} 
1

我喜欢这样做,而不使用regular expressions,所以我将它移植到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; 
    } 
} 
2

stackoverflow solution是伟大的,但现代的浏览器(不包括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)); 
      } 
    ... 
} 

Full Code on Pastebin

编辑:Here's the codeRemapInternationalCharToAscii方法(在pastebin中缺少)。

2

这是我的(速度较慢,但​​有趣写)的杰夫的代码版本:

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

3

我知道这是很老的问题,但由于大多数的浏览器现在支持Unicode的网址我发现了一个很好的解决方案在XRegex,其将除字母一切(所有语言“ - ”)。

这可以用几种编程语言完成。

该模式是\\p{^L}+然后你只需要用它来代替所有非字母' - '。

node.js中的工作示例,带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"