反向正则表达式,从正则表达式创建字符串。

3

我正在研究一个多语言站点,并选择使用每种语言的自定义URL,例如:

/en/cities/paris/
/nl/steden/paris/

两个都指向Cities控制器的Index方法。

每个页面都有切换语言选项,它会查找我的路由以匹配控制器、视图和语言。

因此,如果我在荷兰页面上,它将为英文版本找到正确的网址,这将是'cities'而不是'steden'。

一切都很好,直到我开始使用更复杂的正则表达式。

我有这些正则表达式,它们将匹配我想要的URL:

#^en/cities/([^/]+?)/$#
#^nl/steden/([^/]+?)/$#

在我的代码中,我可以访问正在匹配的变量,在这个例子中是“巴黎”。是否可能“反转”这个正则表达式并打印“en/cities/paris/”?
如果不行...那么我该如何处理同一页面的不同版本的链接,考虑到URL不同...最好尽可能地进行编程。
在一个类似的问题中,有人回答说( https://dev59.com/tFrUa4cB1Zd3GeqPiUqX#7070734 )正则表达式的本质是匹配无限数量的结果...所以可能不可能。
从一个字符串/URL到一组匹配的标准来使用MVC非常容易,但反过来...不太容易,不幸的是。

正则语言可以用来构建语句,但这显然不是你要寻找的。它们构建语句的集合(“语言”),而不是单个语句,因为没有任何东西告诉引擎选择哪个语句。相反,我建议你实现一个URL模式字典,并创建一个查询该字典的函数,例如按城市名称查询。 - arkascha
感谢澄清。我已经决定在我的路由中使用{city},然后包含一些关于应该用什么替换{city}以获得正确的正则表达式的元数据,然后稍后我可以再次更改{city},这次使用正确的数据。它适用于我的复杂正则表达式和仅为纯文本的简单正则表达式。所以我很高兴! - Gerben Jacobs
1个回答

1

是的,这是可能的!针对这种情况,我编写了以下解决方案:

$regex = '#^en/cities/([^/]+?)/$#';
$replace = array('paris');

$result = preg_replace_callback('#^\^|\([^)]*\)|\$$#', function($m)use($replace){
    static $index = 0;
    if($m[0] === '^' || $m[0] === '$'){return '';}
    if(isset($replace[$index])){
        return $replace[$index++];
    }
    return $m[0];
}, substr($regex, 1, -1));
echo $result; // en/cities/paris/

在线演示

我已经使其“灵活”,因此您可以向其中添加更多的值!

$regex = '#^en/cities/([^/]+?)/region/([^/]+?)$#'; // <<< changed
$replace = array('paris', 'nord'); // <<< changed

$result = preg_replace_callback('#^\^|\([^)]*\)|\$$#', function($m)use($replace){
    static $index = 0;
    if($m[0] === '^' || $m[0] === '$'){return '';}
    if(isset($replace[$index])){
        return $replace[$index++];
    }
    return $m[0];
}, substr($regex, 1, -1));
echo $result; // en/cities/paris/region/nord

在线演示


解释:

说明:

$regex = '#^en/cities/([^/]+?)/region/([^/]+?)$#'; // Regex to "reverse"
$replace = array('paris', 'nord'); // Values to "inject"

/*  Regex explanation:
   #   Start delimiter
       ^\^         Match "^" at the begin (we want to get ride of this)
       |           Or
       \([^)]*\)   Match "(", anything zero or more times until ")" is found, ")"
       |           Or
       \$$         Match "$" at the end (we want to get ride of this)
   #   End delimiter
*/

$result = preg_replace_callback('#^\^|\([^)]*\)|\$$#', function($m)use($replace){
    static $index = 0; // Set index 0, note that this variable is only accessible in this (anonymous) function
    if($m[0] === '^' || $m[0] === '$'){return '';} // Get ride of ^/$ at the begin and the end
    if(isset($replace[$index])){ // Always check if it exists, for example if there were not enough values in $replace, this will prevent an error ...
        return $replace[$index++]; // Return the injected value, at the same time increment $index by 1
    }
    return $m[0]; // In case there isn't enough values, this will return ([^/]+?) in this case, you may want to remove it to not include it in the output
}, substr($regex, 1, -1)); // substr($regex, 1, -1) => Get ride of the delimiters
echo $result; // output o_o

注意:此功能仅适用于 PHP 5.3+。

1
这个回答让我有点头痛;p - Ja͢ck

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