mod_rewrite:将下划线替换为短划线

21

我在这里暴露了我的正则表达式技能的尴尬无知, 但是:我目前有一个网站, 其中大量文章的URL被写成"article_name", 而较新的文章则被写成"article-name"。

我想将它们全部改为使用破折号, 那么是否有正则表达式可以用来将旧的URL重写为它们的新版本?

提前感谢您!

6个回答

24

首先,您必须使现有的URL保持一致性。基本上,您必须将所有现有名称规范化为始终使用破折号。好的,您已经做到了这一点。

我们从以下假设开始:

URL大致形式如下:

http://example.com/articles/what-ever/really-doesnt_matter/faulty_article_name

只有在/articles下的URL才需要重写,只有/faulty_article_name部分需要进行消毒。

重大更新,实际可行的方法

对于Apache:

RewriteEngine     On
RewriteRule       ^(/?articles/.*/[^/]*?)_([^/]*?_[^/]*)$ $1-$2 [N]
RewriteRule       ^(/?articles/.*/[^/]*?)_([^/_]*)$       $1-$2 [R=301]

这通常是受 GApple 的回答启发而来。

第一个 /? 确保此代码将在虚拟主机配置和 .htaccess 文件上运行。后者不需要前导斜杠。

然后我添加了 articles/ 部分,以确保规则仅适用于 /articles 中的 URL。

然后,在 URL 中有至少两个下划线时,我们通过规则循环进行。当我们最终只剩下一个下划线时,第二条规则就会生效,用连字符替换它,并进行永久重定向。

呼~


已经实现了规范化 - 我刚迁移到了一个新的 CMS(WordPress),所以现在所有文章都使用破折号作为空格。规则将放在 WordPress 插件中进行重定向,该插件接受静态重定向(不想单独设置50个以上!)或正则表达式。 - Keith Williams
哦,是的 - 那就是URL的确切结构。 - Keith Williams
你的意思是你没有使用apache的mod_rewrite吗?这个WordPress插件是什么?有链接吗?我想了解它如何进行重定向。如果您可以更新您的问题来指出这一事实... - kch
1
啊,我现在明白了,Apache并不像gsub一样执行替换操作,它会期望你捕获想要重用的元素,并在生成最终URL时将它们放回去。这确实让事情变得有些棘手。gnarf的解决方案可能是你最好的选择。 - kch
抱歉回复晚了 - 我在发布这个后就去度假了,刚回来并试了一下。完美解决!回答你的问题,我不想使用 mod_rewrite 是因为我没有访问 HTTP 配置文件的权限(共享主机),而且 WordPress 会将自己的重定向代码插入到 .htaccess 中。 - Keith Williams
它对我创建了无限重定向循环:\ 更多信息请参见:http://stackoverflow.com/questions/32852356/htaccess-rewrite-rule-with-regular-expression - JackTheKnife

14

试试这个:

RewriteRule ^([^_]*)_([^_]*_.*) $1-$2 [N]
RewriteRule ^([^_]*)_([^_]*)$ /$1-$2 [L,R=301]
第一条规则会逐个替换下划线,直到只剩一个或没有下划线。最后一条规则将替换最后一个下划线并执行外部重定向。

1
+1 记得在重定向时添加斜杠。我不确定是否要更新我的vhost-htaccess-agnostic答案以考虑这一点。哦,有那么多括号。 - kch
1
这会破坏那些文件名中带有下划线的图片。 - littlered
1
@littlered 你是对的。这个规则的正确形式应该是:RewriteRule ^([^_]*)_([^_]*_.*).html $1-$2.html [N] RewriteRule ^([^_]*)_([^_]*).html$ /$1-$2.html [L,R=301]它只重写HTML文件。 - dpavlin
1
不使用重定向,这是否可能?我的意思是,使用HTTP 200,是否可以进行此重写? - SenG
1
这似乎会导致无限循环(服务器无响应),对于路径级别大于1的至少有两个下划线的URL,例如http://example.com/a/a_b_c/ - pcworld
@pcworld 如果之前的路径段没有映射到物理文件系统路径,您可能需要在第一个“RewriteRule”指令上添加DPI(Discard Path Info)标志(请注意,尾随斜杠也会创建额外的路径段)。 (在替换项前加上斜杠,以便将其重写为URL路径,而不是文件系统路径,在某些情况下也可能有所帮助。) - MrWhite

2

一个可能不同的思路:

我假设你的“旧格式”和“新格式”将在不同的目录中,如果它们不是,你可能需要考虑让新格式有一个不同的目录名称。

例如:

http://site.com/articles/2008/12/31/new_years_celebration
http://site.com/article/2008/12/31/new_years_celebration

这种情况下,您可以使用mod_rewrite来检测“旧目录”中的任何内容,并将其重定向到“redirector.php”。

尽管在重新考虑后,您的mod_rewrite可能会寻找像这样的东西:

RedirectRule /articles/(.*_.*)  /redirector.php?article=$1

匹配任何带有_的内容并将其发送到重定向器。

在redirector.php中,您可以获取$_SERVER['REQUEST_URI'],并使用preg_replace等工具甚至数据库查询来查找正确的URL以将其重定向 - 以及研究旧URL的点击次数。


这可能会成为一个更容易实现的解决方案。 - kch

1

mod_rewrite如何知道实际的URL应该是什么?您可以将所有文章重写为使用下划线或破折号,但是mod_rewrite无法确定新位置是否存在。

例如,

/I_Like_Bees      存储为   /path/i_like_bees
/I-like-flowers   存储为   /path/i-like-flowers

您想要i-like-bees重写为i_like_bees

  • 如果您将下划线重写为破折号,则找不到i_like_bees
  • 如果您将破折号重写为下划线,则找不到i-like-flowers

如果您始终一致地存储所有文章,则可以轻松制作重写规则。相反,您可能需要编写脚本来检查目录是否存在,并执行301重定向到正确的位置。


抱歉,我的表述可能不够清晰 - 所有文章都将被规范化,我只是想制定规则来处理旧链接并防止链接失效。 - Keith Williams

1

0

这里有一个方法:http://yoast.com/apache-rewrite-dash-underscore/

基本上,它将URL分成下划线两侧的标记,并重新编写标记,用下划线替换。问题是它一次只能替换一个下划线;它将重定向到更接近但不完全正确的URL,然后再次重定向到更接近但可能仍然不正确的URL...

建议通过具有逐步更多下划线和标记的几个重写条件和规则来修复多个重定向,但这将需要与您最长标题中的下划线数量相同的条件和规则。

但请确保添加任何限定词,因为该规则可能会替换您不想更改的路径(例如,图像文件)。


这是一个等待发生“Too many redirects”错误的问题。我建议远离这个解决方案。这是一个巧妙的黑客,但并非没有问题。 - kch
好的,如果使用[N](下一轮)而不是[R=301],这可能会起作用。 - kch

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