将字符串转换为只包含单破折号分隔符的slug

25

我想将一个字符串转换成URL,需要实现以下功能:

  1. 只保留字母数字字符、空格和短横线。
  2. 将空格转换为短横线。

例如:

This, is the URL!

必须返回

this-is-the-url

嗨,詹斯,我对这段代码一无所知,这就是我需要帮助的原因。我唯一知道的是它应该使用 preg_replace(),但我不知道正则表达式应该是什么。谢谢。 - Atif
10个回答

51
function slug($z){
    $z = strtolower($z);
    $z = preg_replace('/[^a-z0-9 -]+/', '', $z);
    $z = str_replace(' ', '-', $z);
    return trim($z, '-');
}

-1:在阅读SilentGhost所写的代码之外,理解他/她意图。虽然这似乎是URL安全的,但代价是信息的丢失。正确的方法是使用urlencode()对数据进行编码以用于URL。 - symcbean
1
把下面这段与程序相关的内容从英语翻译成中文。只返回翻译后的文本: - symcbean
8
@symcbean,urlencode并不是我需要的,因为我想要消除符号而不是将它们转换。所以这正是我想要的。 - Atif
$z = strtolower(trim(preg_replace("/[^\w]+/", "-", $z), "-")) - mario
2
@mario:1. 它不执行相同的处理;2. 这是一个维护的噩梦。 - SilentGhost
显示剩余2条评论

4

首先去除不需要的字符

$new_string = preg_replace("/[^a-zA-Z0-9\s]/", "", $string);

然后将空格改为下划线

$url = preg_replace('/\s/', '-', $new_string);

最后对其进行编码以便使用。
$new_url = urlencode($url);

1
下划线是一个不同的字符:_ 是下划线,- 是连字符。在这样的字符串上使用 urlencode 不会改变任何东西。你还忘记了第一个正则表达式中的连字符,\s 不等同于空格字符。 - SilentGhost

2

OP并没有明确描述slug的所有属性,但这是我从意图中得出的。

我的解释与此帖子所述的完美、有效、简洁的slug一致:https://wordpress.stackexchange.com/questions/149191/slug-formatting-acceptable-characters#:~:text=However%2C%20we%20can%20summarise%20the,or%20end%20with%20a%20hyphen

我发现早期发布的答案都无法始终如一地实现这一点(我甚至没有将问题范围扩展到包括多字节字符)。

  1. 将所有字符转换为小写
  2. 将一个或多个非字母数字字符的序列替换为单个连字符。
  3. 从字符串中删除前导和尾随连字符。

我推荐以下一行命令,它不需要声明仅用一次的变量:

return trim(preg_replace('/[^a-z0-9]+/', '-', strtolower($string)), '-');

我还准备了一份演示,突出展示其他答案中我认为存在的不准确之处。(演示

'This, is - - the URL!' input
'this-is-the-url'       expected

'this-is-----the-url'   SilentGhost
'this-is-the-url'       mario
'This-is---the-URL'     Rooneyl
'This-is-the-URL'       AbhishekGoel
'This, is - - the URL!' HelloHack
'This, is - - the URL!' DenisMatafonov
'This,-is-----the-URL!' AdeelRazaAzeemi
'this-is-the-url'       mickmackusa

---
'Mork & Mindy'      input
'mork-mindy'        expected

'mork--mindy'       SilentGhost
'mork-mindy'        mario
'Mork--Mindy'       Rooneyl
'Mork-Mindy'        AbhishekGoel
'Mork & Mindy'  HelloHack
'Mork & Mindy'      DenisMatafonov
'Mork-&-Mindy'      AdeelRazaAzeemi
'mork-mindy'        mickmackusa

---
'What the_underscore ?!?'   input
'what-the-underscore'       expected

'what-theunderscore'        SilentGhost
'what-the_underscore'       mario
'What-theunderscore-'       Rooneyl
'What-theunderscore-'       AbhishekGoel
'What the_underscore ?!?'   HelloHack
'What the_underscore ?!?'   DenisMatafonov
'What-the_underscore-?!?'   AdeelRazaAzeemi
'what-the-underscore'       mickmackusa

1

试试这个

 function clean($string) {
       $string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
       $string = preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.

       return preg_replace('/-+/', '-', $string); // Replaces multiple hyphens with single one.
    }

使用方法:

echo clean('a|"bc!@£de^&$f g');

将输出:abcdef-g

来源:https://dev59.com/umYq5IYBdhLWcg3w5Ui8#14114419


1

使用intl转换器是一个不错的选择,因为它可以轻松地处理复杂情况,并且只需要一组规则。我添加了自定义规则来说明它有多灵活,以及如何保留最大限度的有意义信息。随时可以删除它们并添加自己的规则。

$strings = [
    'This, is - - the URL!',
    'Holmes & Yoyo',
    'L’Œil de démon',
    'How to win 1000€?',
    '€, $ & other currency symbols',
    'Und die Katze fraß alle mäuse.',
    'Белите рози на София',
    'പോണ്ടിച്ചേരി സൂര്യനു കീഴിൽ',
];

$rules = <<<'RULES'
# Transliteration
:: Any-Latin ;   :: Latin-Ascii ;

# examples of custom replacements
'&' > ' and ' ;
[^0-9][01]? { € > ' euro' ;   € > ' euros' ;
[^0-9][01]? { '$' > ' dollar' ;   '$' > ' dollars' ;
:: Null ;

# slugify
[^[:alnum:]&[:ascii:]]+ > '-' ;
:: Lower ;

# trim
[$] { '-' > &Remove() ;
'-' } [$] > &Remove() ;
RULES;

$tsl = Transliterator::createFromRules($rules, Transliterator::FORWARD);
$results = array_map(fn($s) => $tsl->transliterate($s), $strings);
print_r($results);

演示

不幸的是,PHP手册完全没有关于ICU转换的内容,但你可以在这里找到相关信息。


1

这将在Unix shell中完成(我刚在我的MacOS上尝试过):

$ tr -cs A-Za-z '-' < infile.txt > outfile.txt

我从More Shell, Less Egg的博客文章中得到了这个想法。


0

所有之前的答案都涉及到URL,但是如果有人需要对登录字符串进行清理(例如),并将其保留为文本,则可以使用以下方法:

function sanitizeText($str) {
    $withSpecCharacters = htmlspecialchars($str);
    $splitted_str = str_split($str);
    $result = '';
    foreach ($splitted_str as $letter){
        if (strpos($withSpecCharacters, $letter) !== false) {
            $result .= $letter;
        }
    }
    return $result;
}

echo sanitizeText('ОРРииыфвсси ajvnsakjvnHB "&nvsp;\n" <script>alert()</script>');
//ОРРииыфвсси ajvnsakjvnHB &nvsp;\n scriptalert()/script
//No injections possible, all info at max keeped

0
    function isolate($data) {
        
        $data = trim($data);
        $data = stripslashes($data);
        $data = htmlspecialchars($data);
        
        return $data;
    }

4
请在您的代码中添加更多信息,例如如何使用或者您是如何得出这个答案的。谢谢。 - Mehrad

-1

1
仅提供链接的回答是无用的,尤其当它将会失效时。 您能详细说明一下吗? - Toto
最好将包作为问题下的注释进行推荐。 - mickmackusa

-1

以下将把空格替换为破折号。

$str = str_replace(' ', '-', $str);

接下来的语句将删除除了字母数字和破折号以外的所有字符。(因为在之前的步骤中我们已经用破折号替换了空格。)

// Char representation     0 -  9   A-   Z   a-   z  -    
$str = preg_replace('/[^\x30-\x39\x41-\x5A\x61-\x7A\x2D]/', '', $str);

这相当于什么?

$str = preg_replace('/[^0-9A-Za-z-]+/', '', $str);

提示:要从字符串中删除所有特殊字符,请使用

$str = preg_replace('/[^\x20-\x7E]/', '', $str); 

\x20 是空格的十六进制表示,它是 ASCII 字符的开始,而 \x7E 是波浪号。根据维基百科 https://en.wikipedia.org/wiki/ASCII#Printable_characters 的说法。

请注意:查看 20-7E 的间隔的十六进制列

可打印字符 20hex 到 7Ehex 的代码,称为可打印字符,代表字母、数字、标点符号和一些杂项符号。总共有 95 个可打印字符。


我可以向任何人挑战,证明我是正确的。不知道为什么我被踩了。 - Adeel Raza Azeemi
演示可以在 https://dev59.com/ynA75IYBdhLWcg3w794Y#65280956 找到。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接