2016-03-07 82 views
2

这可能可以用正则表达式来完成,但我不知道。我试图完成的是能够使用给定的分隔符解析字符串,但是当它看到一组括号时,它的解析方式会有所不同。因为我是一个视觉学习,让我向你展示我试图实现的一个例子。 (PS这是越来越从URL解析)PHP复杂的字符串解析

给出字符串输入:

String1,String2(data1,data2,data3),String3,String4 

我如何 “改造” 这个字符串变成数组:

{ 
    "String1": "String1", 
    "String2": [ 
     "data1", 
     "data2", 
     "data3" 
    ], 
    "String3": "String3", 
    "String4": "String4 
} 

格式没有这是严格的,因为我只是试图为我的项目制作一个简单的API。

显然之类的东西

array explode (string $delimiter , string $string [, int $limit = PHP_INT_MAX ])

是行不通的,因为有括号内逗号为好。我试图一次一个一个地看每个角色的手动解析,但是我担心这个性能,而且它实际上并不工作。我粘贴了我的尝试的要点。

https://gist.github.com/Fudge0952/24cb4e6a4ec288a4c492

+1

您可以发布您的输入和期望的输出,所以我们可以更好地理解你想要达到什么目的? –

+0

我从给定的输入发布了期望的输出 – Tim

+0

你可以使用不同的分隔符用于不同级别的字符串儿童吗?例如String1,String2(data1 | data2 | data3),String3,String4 –

回答

1

虽然你可以尝试在逗号分割你的初始字符串,而忽略括号中的第一分东西,这必然使什么这些字符串值实际上是假设(可能需要根据逃避/非转义值关于这些字符串必须包含的内容)。

但是,如果您可以控制数据格式,那么最好从JSON开始。它有明确的定义和良好的支持。

+0

我没有思考JSON的思想为无论如何API只是以JSON输出。 – Tim

+0

但为什么你想要这个化妆语法,而不是json? – VolkerK

+0

@Tim你知道[json_decode](http://php.net/json_decode)是什么东西? – Terminus

1

您可以建立像一个特设的解析器(主要是未经测试):

<?php 
$p = '! 
    [^,\(\)]+ # token: String 
    |,   # token: comma 
    |\(  # token: open 
    |\)  # token: close 
!x'; 
$input = 'String1,String2(data1,data2,data3,data4(a,b,c)),String3,String4'; 

preg_match_all($p, $input, $m); 
// using a norewinditerator, so we can use nested foreach-loops on the same iterator 
$it = new NoRewindIterator(
    new ArrayIterator($m[0]) 
); 

var_export(foo($it)); 

function foo($tokens, $level=0) { 
    $result = []; 
    $current = null; 
    foreach($tokens as $t) { 
     switch($t) { 
      case ')': 
       break; // foreach loop 
      case '(': 
       if (is_null($current)) { 
        throw new Exception('moo'); 
       } 
       $tokens->next(); 
       $result[$current] = foo($tokens, $level+1); 
       $current = null; 
       break; 
      case ',': 
       if (!is_null($current)) { 
        $result[] = $current; 
        $current = null; 
       } 
       break; 
      default: 
       $current = $t; 
       break; 
     } 
    } 
    if (!is_null($current)) { 
     $result[] = $current; 
    } 
    return $result; 
} 

打印

array (
    0 => 'String1', 
    'String2' => 
    array (
    0 => 'data1', 
    1 => 'data2', 
    2 => 'data3', 
    'data4' => 
    array (
     0 => 'a', 
     1 => 'b', 
     2 => 'c', 
    ), 
), 
    1 => 'String3', 
    2 => 'String4', 
) 

(但肯定会失败可怕的形成没有孔的字符串)

或者看看词法分析器/解析器生成器,如eg PHP_LexerGeneratorPHP_ParserGenerator

1

这是preg_match_all()一个解决方案:

$string = 'String1,String2(data1,data2,data3),String3,String4,String5(data4,data5,data6)'; 

$pattern = '/([^,(]+)(\(([^)]+)\))?/'; 

preg_match_all($pattern, $string, $matches); 

$result = array(); 
foreach($matches[1] as $key => $val) 
{ 
    if($matches[3][$key]) 
    { $add = explode(',', $matches[3][$key]); } 
    else 
    { $add = $val; } 
    $result[$val] = $add; 
} 

$json = json_encode($result); 

eval.in demo

模式说明:

([^,(]+)  group 1: any chars except ‘,’ and ‘(’ 
(\(([^)]+)\))? group 2: zero or one occurrence of brackets wrapping: 
    └──┬──┘ 
    ┌──┴──┐ 
    ([^)]+)  group 3: any chars except ‘,’ 
+0

这正是我最初试图实现的!我注意到的一件事是它只支持一级括号,请看这里:https://eval.in/531501有什么方法可以支持任意数量的级别? – Tim

+0

mmhhh ...我不确定100%,但我认为这是不可能的...顺便说一句,我当然不是正则表达式之王,也许别人可以提供更好的答案。但是,如果您可以访问JSON格式的相同数据,我强烈建议您使用它。 – fusion3k

+0

是的,我怀疑我会永远有多层括号,如果它没有使URL看起来丑陋,我会为任何一天JSON去..我多么希望我能接受2答案lol – Tim