2

I'm currently working on my selfmade headline-system. Therefore I'm trying to use #_1# - #_4# for numbering in the text, which should be converted in headlines then. Therefore, you write the text of the headline between the number and the second #. For example:

#_1Testheadline#
#_2second headline under the first one#
#_2another headline under the first one#
#_1second headline (not under the first one)#

would become

1. Testheadline
1.1 second headline under the first one
1.2 another headline under the first one
2. second headline (not under the first one)

Hope you understand what I mean.

So the first example (so with #_1# in it) is written in a WYSIWYG-Editor, so this is normal html code, which is then stored in a variable in a database.

What I want now is when I get this variable from database, I want to replace all the pseudo-headlines by real headlines (to view), so the first example would become the second.

Therefore I need to find all occurences of #_1, replace with <h1>, go on until the # and replace it with </h1>. Same for the second, third and fourth "layer" of headings. If I'm able to do that, I still wouldn't have finished, because now, the headings need their numbers in front, therefore I could simply use 4 counters:

var firstlayercount = 0,
  secondlayercount = 0;
var thirdlayercount = 0,
  fourthlayercount = 0;

and increase and set them back to 0, depending on which headline was found, so actually this should be the easier part. But the harder question is, how to find the #_1 in the string, replace it and then go to the # and replace it, too? And do this several times?

nameless
  • 1,483
  • 5
  • 32
  • 78

1 Answers1

2

Use preg_replace_callback function

$str = '#_1Testheadline#
#_2second headline under the first one
#_2another headline under the first one
#_1second headline (not under the first one)';

// Current level
$level = 0;
echo preg_replace_callback('/#?\s*#_(\d)+/', 
  function($x) use (&$level) {
    // Close previous tag if it is
    $out = ($level ?  "</h{$level}>\n" : '');
    // Save current level and open tag  
    $level = $x[1];
    return $out .  "<h{$level}>"; 
  },
  // Don't forget to close the last tag
  $str) . "<h{$level}>";

result

<h1>Testheadline#</h1>
<h2>second headline under the first one</h2>
<h2>another headline under the first one</h2>
<h1>second headline (not under the first one)<h1>  

UPDATE 1

You can use the same approach to build ordered list

$level = 0;

echo preg_replace_callback('/#?\s*#_(\d)+/', 
  function($x) use (&$level) { 
    if($x[1] > $level) $out = "\n<ol>\n";
    else if ($x[1] < $level) $out = "</li>\n</ol>\n";
    else $out = "</li>\n";
    $level = $x[1];
    return $out .  "<li>"; 
  },
  $str) . "</li>\n</ol>\n";

result

<ol>
   <li>Testheadline#
   <ol>
      <li>second headline under the first one</li>
      <li>another headline under the first one</li>
  </ol>
  <li>second headline (not under the first one)</li>
</ol>

UPDATE 2

Stylise lists by css

<STYLE>
ol {
  list-style: none; 
  counter-reset: li; 
}
li:before {
   counter-increment: li; 
   content: counters(li,".") ". "; 
}
</STYLE>
<ol>
   <li>Testheadline#
   <ol>
      <li>second headline under the first one</li>
      <li>another headline under the first one</li>
  </ol>
  <li>second headline (not under the first one)</li>
</ol>

UPDATE 3

Making numbering by php

$cnts = [ 0 ];
echo preg_replace_callback('/#?\s*#_(\d)+/', 
  function($x) use (&$cnts) {
    $level = $x[1]-1;
    if($level < count($cnts)-1) $cnts = array_slice($cnts, 0, $level+1);
    if (! isset($cnts[$level])) $cnts[$level] = 1;
    else $cnts[$level]++;
    $temp = array_slice($cnts, 0, $level+1);
    return "\n" . implode('.', $temp) . ". "; 
  },
  $str) ;

result

1. Testheadline
1.1. second headline under the first one
1.2. another headline under the first one
2. second headline (not under the first one)
Community
  • 1
  • 1
splash58
  • 26,043
  • 3
  • 22
  • 34
  • I think that this code not have to close another tags than those it produces. So for it, start level is always zero – splash58 Jan 29 '18 at 07:33
  • thanks for that piece of code. In general, it seems to be working, but for some reason, all headings still include the second (closing) `#`, which shouldn't be like that. Any ideas why? – nameless Jan 29 '18 at 07:40
  • also, as, to be honest, I don't completely understand what's happening in your code, how would I do the counter thing, to increase the numbers as well, so it would become numbered instead of only headings (like in my example above)? – nameless Jan 29 '18 at 07:44
  • aaah, now I got the problem, you don't have the closing `#` in your code (I forgot it above as well first), this is why.. Ofcourse, the headings won't follow one after another, that's why I use the closing ones as well, so its `#_1Test#Here is some normal text, no headings #_2Second heading#` and so on, if you know what I mean – nameless Jan 29 '18 at 07:49
  • regarding your update, sorry to confuse you, the "normal" html ordered list won't work for me, as I need to have it as in my example above, not only with indention, but something like `1, 1.1, 1.2, 1.2.1, 1.2.2, 2` and so on, and this is not possible with the ordered lists of html, thats basically what that hole project is about.. – nameless Jan 29 '18 at 07:51
  • where we get to the next problem, I knew why I tried to implement the numbers with a counter in php, this is because the display of the html later happens in a pdf generated with TCPDF, which doesn't know the list style type, but the pdf is the place, where it's important to be displayed correctly... – nameless Jan 29 '18 at 08:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164070/discussion-between-nameless-and-splash58). – nameless Jan 29 '18 at 08:30
  • Is it possible to combine both as well? So the `

    ` - `

    ` tags, combined with the numbering?

    – nameless Jan 29 '18 at 09:27
  • you're there? is this possible? – nameless Jan 29 '18 at 09:56
  • but how? tried to just combine the code by adding the code of the first part of the answer to update 3 code, but its not working because of two times `return` – nameless Jan 29 '18 at 09:59
  • and levels contain different values. – splash58 Jan 29 '18 at 10:00
  • and levels contain different values in the 1st and in the last codes. Don't forget to rename one of them – splash58 Jan 29 '18 at 10:07
  • I'm glad. Good luck! – splash58 Jan 29 '18 at 10:46