首先,我认为您的正则表达式需要一些修复。让我们看看你有什么:
test.com(\/\??index_.*.php\??(.*)|\/\?(.*)|\/|)+(\s)*(?!.)
在index... 的开头使用可选的? 的情况已经被第二种替代方案处理了:
test.com(\/index_.*.php\??(.*)|\/\?(.*)|\/|)+(\s)*(?!.)
现在您可能只希望允许第一个(.*),如果之前确实有一个文字?。否则你将匹配test.com/index_fb2.phpanystringhereandyouprobablydon'twantthat。所以移动相应的可选标记:
test.com(\/index_.*.php(\?(.*))?|\/\?(.*)|\/|)+(\s)*(?!.)
现在.* 尽可能多地使用任何字符。此外,php 前面的 . 可以使用任何字符。这意味着您将允许test.com/index_fb2php 和test.com/index_fb2.html?someparam=php。让我们将其设为文字 . 并且只允许非问号字符:
test.com(\/index_[^?]*\.php(\?(.*))?|\/\?(.*)|\/|)+(\s)*(?!.)
现在第一个、第二个和第三个选项可以合并为一个,如果我们也将文件名设为可选:
test.com(\/(index_[^?]*\.php)?(\?(.*))?|)+(\s)*(?!.)
最后,+ 可以被删除,因为里面的(.*) 已经可以处理所有可能的重复。同样(something|) 与(something)? 相同:
test.com(\/(index_[^?]*\.php)?(\?(.*))?)?(\s)*(?!.)
看到您的输入示例,这似乎更接近您实际想要匹配的内容。
然后回答你的问题。 (?!.) 的作用取决于您是否使用singleline 模式。如果你这样做了,它就断言你已经到达了字符串的末尾。在这种情况下,您可以简单地将其替换为\Z,它始终匹配字符串的结尾。如果你不这样做,那么它断言你已经到了一行的末尾。在这种情况下,您可以使用$,但您还需要使用多行模式,以便$ 也匹配行尾。
所以,如果您使用singleline 模式(这可能意味着每个字符串只有一个 URL),请使用:
test.com(\/(index_[^?]*\.php)?(\?(.*))?)?(\s)*\Z
如果您不使用singleline 模式(这可能意味着您可以在自己的行中有多个 URL),您还应该使用multiline 模式和这种锚:
test.com(\/(index_[^?]*\.php)?(\?(.*))?)?(\s)*$