1

I was wondering if it's possible to do something like this.

I'm having the following string:

Parent1@MiddleA%Child|Child|Child|MiddleB%Child|Child|Child|Parent2@MiddleA%|Child

And I'd like to explode it into something like:

-Parent1
---MiddleA
------Child
------Child
------Child
---MiddleB
------Child
------Child
------Child
-Parent2
---MiddleA
------Child

I don't understand how to explode it and then explode it again to create an output like above.

The idea is that every parent will be identified with a trailing @, every child of that parent will have a trailing % and every child of that child will have a trailing|.

kenorb
  • 155,785
  • 88
  • 678
  • 743
Jack Smith
  • 55
  • 1
  • 8
  • 1
    is there a reason for using "your own" (un-)serializing method and not the PHP "serialize" & "unserialize"? (or JSON, for that matter) – Roman Oct 29 '11 at 12:21
  • You might be able to customize a JSON parser... –  Oct 29 '11 at 12:21
  • i don't even know what php offers there or what json is. I'll have to do some searching. – Jack Smith Oct 29 '11 at 14:26

3 Answers3

0

I guess there's no way to automatically explode it to multi-dimension array, so you have to write your specific algorythm to do the job. There is a logical sequence in the string so it can easilly be transformed. Start with exploding by "@", then for each element explode by "A%", and then by "|".

Deniss Kozlovs
  • 4,761
  • 2
  • 28
  • 35
0
<?php
$string = "Parent1@MiddleA%Child|Child|Child|MiddleB%Child|Child|Child|Parent2@MiddleA%|Child";

$explode1 = explode ("@",$string);

foreach ($explode1 as $str)
{

  $explode2 = explode("|", $str);

  foreach ($explode2 as $str2)
  {
    $explode3 = explode ("%", $str2);

        foreach($explode3 as $str3)
        {
        echo ($str3 != "") ? $str3 . "<br/>" : "";
        }
  }

}
?>

will output:

Parent1
MiddleA
Child
Child
Child
MiddleB
Child
Child
Child
Parent2
MiddleA
Child
Luke
  • 22,826
  • 31
  • 110
  • 193
  • Thank you! That makes sense. I never learnt the foreach function... how did that not occur to me?! – Jack Smith Oct 29 '11 at 12:32
  • This looks like a flat list, I wonder this is really fitting for what OP asked for. – hakre Oct 29 '11 at 12:34
  • It's true, I can split it up if the OP wishes me to? I got the impression that he just wanted the gist of how to explode() strings... – Luke Oct 29 '11 at 12:37
  • Hmm, yeah I was trying to figure out how to also style each level. I'm experimenting now, but I'm not familiar with the function. I'm just looking at tizag, but it's not making a lot of sense to me. – Jack Smith Oct 29 '11 at 12:43
  • Is there any flexibility in your initial string? What is that you're trying to create? – Luke Oct 29 '11 at 12:47
  • Not really. because I didn't want to create multiple columns for the database. I wanted just one string that could be split into multiple virtual columns, so to speak. – Jack Smith Oct 29 '11 at 12:51
  • @JackSmith: Why not prefix every label with the number of the level and a `@`. You then can separate elements with `|`. That done you first explode on `|`, then explode on `@`. You've got the level and the label then per each element. Job done. – hakre Oct 29 '11 at 12:55
  • @hakre because I don't want a list style. – Jack Smith Oct 29 '11 at 12:57
  • @JackSmith: Then look at my answer, it keeps your style, are you running into any problem with it? If so leave a comment below it. – hakre Oct 29 '11 at 13:00
0

The data you give as input in your question:

Parent1@MiddleA%Child|Child|Child|MiddleB%Child|Child|Child|Parent2@MiddleA%|Child

is not really well fitting to produce the output you ask for. It's even syntactically incorrect at it's end, the delimiters in MiddleA%|Child specifically.

Correnting this, you can easily do it with preg_split:

$str = 'Parent1@MiddleA%Child|Child|Child|MiddleB%Child|Child|Child|Parent2@MiddleA%Child|';

$elements = preg_split('~([^@%|]+?[@%|])~', $str, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

$types = '@%|';
foreach($elements as $element)
{
    $label = substr($element, 0, -1);
    $type = substr($element, -1);
    $indentValue = strpos($types, $type);
    if (FALSE === $indentValue) throw new Exception('Invalid string given.');
    $indent = str_repeat('-', $indentValue * 2 + 1);
    printf("%s %s\n", $indent, $label);
}

If you don't have the input string in a valid format, you need to fix it first, e.g. with an appropriate parser or you need to react on the bogus cases inside the foreach loop.

Edit: This is an modified example that turns the string into a tree-like structure so you can output it with nested foreach loops:

$str = 'Parent1@MiddleA%Child|Child|Child|MiddleB%Child|Child|Child|Parent2@MiddleA%Child|';

$types = '@%|';
$pattern = sprintf('~([^%1$s]+?[%1$s])~', $types);
$elements = preg_split($pattern, $str, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

$tree = array();
foreach($elements as $element)
{
    $label = substr($element, 0, -1);
    $type = substr($element, -1);
    $indentValue = strpos($types, $type);
    if (FALSE === $indentValue) throw new Exception('Invalid string given.');

    $add =& $tree;
    for($i = $indentValue; $i--;)
    {
        $index = max(0, count($add)-1);
        $add =& $add[$index][1];
    }
    $add[] = array($label, array());
    unset($add);
}

foreach($tree as $level1)
{
    echo '<div>', $level1[0], "\n";
    foreach($level1[1] as $level2)
    {
        echo '  <h3>', $level2[0], '</h3>', "\n";
        foreach($level2[1] as $level3)
        {
            echo '    <span>', $level3[0],'</span>', "\n";
        }
    }
    echo '</div>', "\n";
}

(Demo) - Hope this is helpful.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • Sorry. I didn't see this. I'm not sure how to change this from giving an indent to saying if its a level 1 do this style, if level 2, do this other html. Do you get what I mean? – Jack Smith Oct 29 '11 at 13:07
  • Wait, I think I might have it. BRB. Thank you, too. – Jack Smith Oct 29 '11 at 13:10
  • @JackSmith: Check `$indentValue`, it's 0 for level 1, 1 for level 2 and so on. If it's `FALSE` an error occured. – hakre Oct 29 '11 at 13:11
  • I can't figure it out. I'm trying to get it so that there's a $start $value $end, with $value being the $label and $start and $end being the enclosing html. – Jack Smith Oct 29 '11 at 13:23
  • What type of HTML do you want to output? An `
      • ...` type of list? You need to tell in your question, otherwise it's not known. The output in my question was for what you've given in your question what you want to do, you need to share more in your question if you'd like me to share more in the answer.
    – hakre Oct 29 '11 at 13:26
  • No, I don't want any list style. Just any HTML that I can change later, probably divs with different classes. – Jack Smith Oct 29 '11 at 13:29
  • Level 1: Start
    End
    Level 2: Start

    End

    Level 3: Start End
    – Jack Smith Oct 29 '11 at 13:29
  • @JackSmith: Edited the answer, this should do what you ask for or at least is easy to modify. – hakre Oct 29 '11 at 13:57
  • That works wonderfully. Thank you so much! :D. I'm just reading through it to try to understand it all. I see the general layout, maybe I should read up on foreach more. – Jack Smith Oct 29 '11 at 14:04
  • Just a question. Because some content might have a % or @ how would I go about altering the code so that the separators are different and don't so that the string doesn't get mixed with a separator, if you get what I mean. I mean... what other separators could I use? or is there a way to have my string split by a combination of characters such as @@ %% and || instead of single characters? – Jack Smith Oct 29 '11 at 14:19
  • It's possible but more complicated. If your structure becomes more complicated, use an array instead, and take a look into json_encode / decode. It's pretty similar to what you try to achieve and has already solved the problems you start to run into. And it ships with PHP. I suggest you look into that instead. – hakre Oct 29 '11 at 14:43