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?

2
  • is this PHP or JS? you have added tag for PHP but code is of JS Commented Jan 29, 2018 at 6:38
  • PHP, javascript would be easier, but needs to be PHP infact.. Commented Jan 29, 2018 at 6:38

1 Answer 1

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)
Sign up to request clarification or add additional context in comments.

13 Comments

I think that this code not have to close another tags than those it produces. So for it, start level is always zero
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?
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)?
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
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..
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.