我有一个自定义的路由类,该类允许我根据请求进行匹配:
d3.event.sourceEvent.stopPropagation();
将匹配以下链接:
'/[*:cat1]/[*:cat2]/?[*:cat3]/?[*:cat4]/?[p:page]/?'
如您所见? /后表示该参数是可选的。
我的问题出在[p:page] /?这也是可选的。
category-one/page-2/ category-one/cat-two/page-2/ category-one/cat-two/cat-three/page-2/ category-one/cat-two/cat-three/cat-four/page-2/
我的问题是,当我尝试匹配此链接
/category-one/cat-two/page-2/
它将给我这些参数:
category-one/
category-one/cat-two/
category-one/cat-two/cat-three/
category-one/cat-two/cat-three/cat-four/
代替
cat1 => category-one
cat2 => cat-two
cat3 => page-2
我正在使用此生成的正则表达式:
cat1 => category-one
cat2 => cat-two
page => page-2
感谢您的帮助。谢谢! 亚历克斯
答案 0 :(得分:1)
我将使用令牌词法分析器/解析器方法。我在git中心页面上有一些示例:
https://github.com/ArtisticPhoenix/MISC/tree/master/Lexers
这些是我用来回答SO的其他问题,一个是JSON对象解析器,而不是JSON字符串。如果"
无法处理的属性周围没有json_decode
,这将是格式错误的JSON。另一个是HTML缩小器(虽然是OOP样式,但概念相同),您可以从中排除<textarea>
标签之类的东西,因为那里的空白很重要。因此,您可以使用此方法进行几乎任何形式的文本处理。
我修改了一个,但是我真的不知道您想要输出什么或想要使用它做什么,但是它应该可以帮助您入门。可能您必须将其集成到您的URL路由类中,我不知道它的外观。但这是比简单的preg_match
更好的方法,因为它为您提供了在比赛的每个片段上执行复杂逻辑的地方。
//don't edit this part.
function parse($subject, $tokens)
{
$types = array_keys($tokens);
$patterns = [];
$lexer_stream = [];
$result = false;
foreach ($tokens as $k=>$v){
$patterns[] = "(?P<$k>$v)";
}
$pattern = "/".implode('|', $patterns)."/i";
if (preg_match_all($pattern, $subject, $matches, PREG_OFFSET_CAPTURE)) {
//print_r($matches);
foreach ($matches[0] as $key => $value) {
$match = [];
foreach ($types as $type) {
$match = $matches[$type][$key];
if (is_array($match) && $match[1] != -1) {
break;
}
}
$tok = [
'content' => $match[0],
'type' => $type,
'offset' => $match[1]
];
$lexer_stream[] = $tok;
}
$result = parseTokens( $lexer_stream );
}
return $result;
}
//make changes here to how the tokens are dealt with
function parseTokens( array &$lexer_stream ){
$result = [];
while($current = current($lexer_stream)){
$content = $current['content'];
$type = $current['type'];
switch($type){
case 'T_EOF': return;
//custom code for you tokens.
case 'T_DELIMTER':
case 'T_BASE':
//ignore these
next($lexer_stream); //don't forget to call next
break;
case 'T_CAT':
$cat = substr($content, 4);
echo "This is Cat ".$cat."\n";
next($lexer_stream);
break;
case 'T_PAGE':
$page = substr($content, 5);
echo "This is Page".$page;
next($lexer_stream);
break;
//catch all token
case 'T_UNKNOWN':
default:
print_r($current);
trigger_error("Unknown token $type value $content", E_USER_ERROR);
}
}
if( !$current ) return;
print_r($current);
trigger_error("Unclosed item $mode for $type value $content", E_USER_ERROR);
}
/**
* token should be "name" => "regx"
*
* Order is important
*
* @var array $tokens
*/
$tokens = [
'T_EOF' => '\Z',
'T_DELIMTER' => '\/',
'T_BASE' => 'category-one',
'T_CAT' => 'cat-(?:one|two|three|four)',
'T_PAGE' => 'page-\d+',
'T_UNKNOWN' => '.+?',
];
$subject = '/category-one/cat-two/page-2/';
parse($subject, $tokens);
echo "\n\n========================================\n\n";
$subject = '/category-one/cat-two/cat-three/cat-four/page-2/';
parse($subject, $tokens);
您可以在操作中here看到它
以上代码的输出:
//$subject = '/category-one/cat-two/page-2/';
This is Cat two
This is Page2
========================================
//$subject = '/category-one/cat-two/cat-three/cat-four/page-2/';
This is Cat two
This is Cat three
This is Cat four
This is Page2
它是如何工作的,它基本上全部使用了preg match,但是它被包装在一个令人信服的类型处理中,以使处理输出变得更容易并构建正则表达式。因此,您可以使用一个更小的,更易于处理的而不是一个完整的Regx。乍一看似乎很复杂,但实际上一旦您了解了它的功能,它就会变得非常容易。
您甚至可以通过在parseTokens
函数中添加一些逻辑来检查顺序。这应该是您唯一需要编辑内容的地方,主要是在令牌切换语句中。
它创建的regx就是这样
/(?P<T_EOF>\Z)|(?P<T_DELIMTER>\/)|(?P<T_BASE>category-one)|(?P<T_CAT>cat-(?:one|two|three|four))|(?P<T_PAGE>page-\d+)|(?P<T_UNKNOWN>.+?)/i
因此,当我在或cat-(?:one|two|three|four)
中添加一个非捕获组时,您无法添加子捕获组注释。但是您稍后可以使用substr
进行分隔,因此没什么大不了的。
\Z
有点晦涩,但它只匹配字符串的末尾而没有捕获任何东西。
处理部分也这样称呼(在parse
中):
$result = parseTokens( $lexer_stream );
...
return $result;
因此,您可以将通过parse
函数返回的数据返回到调用它的位置(如果需要)
$something = parse($subject,$tokens);
我现在没有时间详细介绍什么是词法分析器或它是如何工作的。因此,希望这足以让您入门。
更新
这是一个好的开始,但是您的代码非常具体,
为了解决这个问题(不要误会我的意思或以错误的方式处理这个问题),我觉得我需要进一步解释。
这是非常普遍的
$tokens = [
'T_EOF' => '\Z',
'T_DELIMTER' => '\/',
'T_BASE' => 'category-one',
'T_CAT' => 'cat-(?:one|two|three|four)',
'T_PAGE' => 'page-\d+',
'T_UNKNOWN' => '.+?',
];
这是非常具体的
`^(?:/(?P<cat1>[^/\.]+))(?:/(?P<cat2>[^/\.]+/)?)(?:(?P<cat3>[^/\.]+/)?)(?:(?P<cat4>[^/\.]+/)?)(?:(?P<page>(a^)|(?:pag-)(\d+)/)?)$`u
如果必须进行编辑,这将是一个巨大的问题,如果您要转到书籍或其他内容该怎么办。您将如何扩展呢?我什至不知道从哪里开始。
我给你的数组方法,只需添加即可
$tokens = [
'T_EOF' => '\Z',
'T_DELIMTER' => '\/',
'T_BASE' => 'category-one',
'T_CAT' => 'cat-(?:one|two|three|four)',
'T_PAGE' => 'page-\d+',
'T_BOOK' => 'book-\w+',
'T_UNKNOWN' => '.+?',
];
然后修改switch语句:
case 'T_BOOK':
///do something
break;
Bam可以以简洁明了的方式做任何您想做的事情。您可以非常轻松地添加所需的复杂逻辑,错误检查等。