我需要一些帮助来创建重定向,我试图将所有字符替换-
为+
,但两者都是特殊字符,并且只想在 URL 包含时执行此操作?s=
。
这是一个例子
example.com/?s=i-need-to-rewrite-this-url
example.com/?s=i+need+to+rewrite+this+url
这是我所拥有的,我已经尝试使用()
或""
但没有用
RewriteEngine on
RewriteRule ^?s=(.*)\-(.*)$ ?s=$1\+$2 [L,R=301]
我很感激任何帮助。谢谢。
答案1
我试图将所有替换
-
为+
,但两者都是特殊字符
这些字符没有什么特别的“特殊”之处。至少,在它们将要使用的上下文中没有。-
(连字符)是范围说明符在正则表达式字符类中使用时,否则它只是一个连字符,并且可以安全地在 URL 的查询字符串部分使用未编码的字符(我们不需要在正则表达式字符类中使用它)。+
(加号)是一个正则表达式量词,但我们不需要在正则表达式中使用它,只需要在替换字符串(该RewriteRule
指令的第二个参数,不是正则表达式)。这+
是一个编码的空间当在 URL 的查询字符串部分使用时 - 我想您已经知道这一点,这就是为什么需要重定向请求(尽管由于这是 URL 参数值的一部分,所以很好奇为什么无法在应用程序中解析它)。
但有一点需要注意,因为+
URL 是经过编码的空间我们确实需要在指令上使用NE
( noescape
) 标志RewriteRule
来防止 mod_rewrite 在重定向响应中将 URL 编码+
为%2B
(文字+
)。 (对于我们可能从中捕获的任何其他 % 编码字符也是如此QUERY_STRING
- 此服务器变量未经过 % 解码。)
RewriteRule ^?s=(.*)\-(.*)$ ?s=$1\+$2 [L,R=301]
这RewriteRule
图案(第一个参数) 仅匹配 URL 路径,而不匹配查询字符串。因此,RewriteRule
单独的指令永远不会匹配查询字符串。顺便说一句,?
是一个特殊的正则表达式字符(前一个标记的 0 或 1 量词)并且^
(前一个标记)不可量化,所以我很惊讶这是否会编译(导致 500 内部服务器错误)。正则表达式中的文字?
需要使用反斜杠转义。
如上所述,NE
此处需要标志。并且+
不需要在替换字符串,因为它在这里没有特殊含义(它不是正则表达式)。此外,由于相对替换字符串(即?s=$1\+$2
),除非您已经定义,否则RewriteBase
这会导致格式错误的重定向。
为了匹配查询字符串,你需要一个额外的状况(RewriteCond
指令)并与服务器变量进行匹配QUERY_STRING
。因此,作为第一次尝试,您可以执行以下操作:
# First attempt (inefficient when multiple "-" are present)
RewriteCond %{QUERY_STRING} ^s=([^&]*)-([^&]*)
RewriteRule ^$ /?s=%1+%2 [NE,R=301,L]
请注意,%1
和%2
反向引用(与 等相反$1
)包含从前面捕获的值条件模式(RewriteCond
指令),而不是RewriteRule
图案(在这种情况下仅匹配空字符串)。
(注意:您应该始终先使用 302(临时)重定向进行测试,以避免潜在的缓存问题,并确保在测试之前清除所有中间缓存。)
我假设s
是仅有的URL 参数。根据上述规则,后面的任何其他 URL 参数都将被丢弃。
然而,上面的代码效率很低,因为它会为 的每个实例触发一次外部重定向-
。因此,您的示例/?s=i-need-to-rewrite-this-url
会触发 5 次重定向。
解决方案
与上述方法不同,您应该-
在内部递归替换除一个之外的所有项,并且仅在替换完所有项后才触发外部重定向(并替换最后一个项-
)-
。为此,我们需要进行额外的重写以执行内部替换。例如:
# Internally replace all but the last "-" with "+" in the URL param
RewriteCond %{QUERY_STRING} ^s=([^&]*-[^&]*){2}
RewriteCond %{QUERY_STRING} ^s=([^&]*)-([^&]*)
RewriteRule ^$ ?s=%1+%2 [N=20]
# Replace the last "-" and redirect
RewriteCond %{QUERY_STRING} ^s=([^&-]*)-([^&-]*)
RewriteRule ^$ /?s=%1+%2 [NE,R=301,L]
首先状况检查正则表达式的规则^s=([^&]*-[^&]*){2}
只是确定 URL 参数值中至少有 2 个连字符s
。(否则将跳过该规则并直接转到第二条/重定向规则。)第二条状况然后 捕获 最后 查询 字符串 的 相关 部分-
, 然后 在 接下来 中 使用 这些 部分RewriteRule
.
该N
标志使重写引擎立即重新启动。20
对迭代次数设置了限制(Apache 2.4+) - 所以我假设连字符不超过 20+1 个(最后一个连字符在第二个/重定向规则中被替换)。
因为我们知道在处理第二条规则时 URL 参数中最多只剩下 1 个连字符,所以我将连字符添加到正则表达式字符类中作为优化,以避免不必要的回溯。
未来
有一个replace
Apache 表达式新增函数,顾名思义,它允许您搜索/替换字符串中的字符,但我认为这在最新的公共版本中尚未实现。但这可能会允许您在单个规则中执行类似以下操作:
RewriteCond %{QUERY_STRING} ^s=[^&]*-
RewriteCond expr "replace(%{QUERY_STRING},'-','+') =~ /^s=([^&]+)/"
RewriteRule ^$ /?s=%1 [NE,R=301,L]