0

I'm trying to create a regex which will create html out of markup code.

When trying to replace a part of the [table] markup, it only replaces the last occurence.

I have the following regex (PHP):

/(\[table].*)\[\|](.*\[\/table])/s

Replace pattern:

$1</td><td>$2

And the following test string:

[table]<thead>
<th>head1</th><th>head2</th></thead>
[*]test1[|]test2
[*]test1[|]test2
[/table]

It should produce the following:

[table]<thead>
<th>head1</th><th>head2</th></thead>
[*]test1</td><td>test2
[*]test1</td><td>test2
[/table]

but it actualy procudes this:

[table]<thead>
<th>head1</th><th>head2</th></thead>
[*]test1[|]test2
[*]test1</td><td>test2
[/table]

The problem with that is, that [|] is used in other markup codes to but should not be replaced with </td><td>


To clarify: I have a table "bb-code"

[table]
[**]header1[||]header2[||]header3[||]...[/**]
[*]child1.1[|]child1.2[|]child1.3[|]...
[*]child2.1[|]child2.2[|]child2.3[|]...
[*]child3.1[|]child3.2[|]child3.3[|]...
[*]...[|]...[|]...[|]...
[/table]

I want this to become this:

<table class="ui compact stripet yellow table">
    <thead>
        <tr>
            <th>header1</th>
            <th>header2</th>
            <th>header3</th>
            <th>....</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>child1.1</td>
            <td>child1.2</td>
            <td>child1.3</td>
            <td>...</td>
        </tr>
        <tr>
            <td>child2.1</td>
            <td>child2.2</td>
            <td>child2.3</td>
            <td>...</td>
        </tr>
        <tr>
            <td>child3.1</td>
            <td>child3.2</td>
            <td>child3.3</td>
            <td>...</td>
        </tr>
    </tbody>
</table>
KillTrot
  • 63
  • 7
  • This regex will only ever replace one value as it can only match one value (starting with `[table]` and ending with `[/table]`). It will either match the last as it currently stands, or if you change `(\[table].*)` to `(\[table].*?)` it will match the first. – Nick Nov 19 '19 at 10:44
  • @Nick how can I make it replace every occurrence of the pattern? – KillTrot Nov 19 '19 at 10:45
  • Did you use something like `$filteredContent = preg_replace($pattern, $replacement, $content);`? – Ivan86 Nov 19 '19 at 10:48
  • You would need to match only on something which is repeated. e.g. you could replace `/\[\|]/` with ``. – Nick Nov 19 '19 at 10:49
  • @Ivan86 Yes I did – KillTrot Nov 19 '19 at 10:50
  • @Nick The problem with that is, that ```[|]``` is used in other markup codes to but should not be replaced with `````` – KillTrot Nov 19 '19 at 10:51
  • 1
    Use `preg_replace_callback('~\[table][^[]*(?:\[(?!/?table])[^[]*)*\[/table]~', function($m) { return str_replace('[|]', '', $m[0]); }, $str)` – Wiktor Stribiżew Nov 19 '19 at 10:52
  • @Nick you're right, didn't catch that – Ivan86 Nov 19 '19 at 10:53
  • @WiktorStribizew Thanks alot, this works. Would you answer it outside the comment function so I can mark it as the solution? – KillTrot Nov 19 '19 at 10:58
  • Only if @mickmackusa reopens the question. – Wiktor Stribiżew Nov 19 '19 at 11:00
  • I need to check if my duplicates are _wrong_. I suppose this vital detail: "**The problem with that is, that [|] is used in other markup codes to but should not be replaced with **" needs to be edited into the question. The question is currently not realistic/accurate enough. We shouldn't need to read comments to get the full story. – mickmackusa Nov 19 '19 at 11:03
  • @WiktorStribiżew why don't you re-open it? – Nick Nov 19 '19 at 11:04
  • @Nick Wiktor would like me to use my Golden Pry Bar. – mickmackusa Nov 19 '19 at 11:06
  • @WiktorStribizew As I said, it works now. But how do I replace the ```[*]``` until ```newline``` now? I don't fully understand your Regex, I think it would help me, if you could explain it shortly. @mickmackusa I'll edit the important part into the question – KillTrot Nov 19 '19 at 12:39
  • What newline? You should explain what you are doing, add all details to the question. – Wiktor Stribiżew Nov 19 '19 at 12:41
  • I've added some more information – KillTrot Nov 19 '19 at 13:07
  • @Wiktor the question is now unhammered. – mickmackusa Nov 19 '19 at 20:07
  • I don't know if the revenge DVs on my correct, working, explained answers are a result of this page or this [whistleblow](https://stackoverflow.com/questions/6875913/simple-how-to-replace-all-between-with-php#comment104142993_6875963) from 8 hours ago (My first scathing comment was deleted, so I've recommented), but when will people learn that DVing good content is an abuse on this site and its visitors AND does me no harm. – mickmackusa Nov 19 '19 at 20:43

1 Answers1

0

Okay, I had a few minutes to spare on my mobile phone before bedtime, so I ran with Wiktor's comment and whacked up a series of preg_ functions to try to convert your bbcode to html. I don't have any experience with bbcode, so I am purely addressing your sample input and not considering fringe cases. I think php has a bbcode parser library somewhere, but I don't know if your bbcode syntax is the standard.

Some break down of the patterns implemented.

First, isolate each whole [table]...[/table] string in the document. (Regex101 Demo) ~\[table]\R*([^[]*(?:\[(?!/?table])[^[]*)*)\R*\[/table]~ will match the strings and pass the fullmatch as $m[0] and the substring between the table tags as $m[1] to BBTableToHTML().

Next, BBTableToHTML() will make 3 separate passes over the $m[1] string. Each of those patterns will send their respective matched strings to the associated custom function and return the modified string.

Before sending the updated $m[1] from BBTableToHTML() back to the echo, your desired <table...> and </table> tags will bookend $m[1].

Demos of the preg_replace_callback_array() patterns:

  1. ~\[\*\*]([^[]*(?:\[(?!/?\*\*])[^[]*)*)\[/\*\*]~ https://regex101.com/r/thINHQ/2
  2. ~(?:\[\*].*\R*)+~ https://regex101.com/r/thINHQ/3
  3. ~\[\*](.*)~ https://regex101.com/r/thINHQ/4

Code: (Demo)

$bbcode = <<<BBCODE
[b]Check out this demo[/b]
¯\_(ツ)_/¯
[table]
[**]header1[||]header2[||]header3[||]...[/**]
[*]child1.1[|]child1.2[|]child1.3[|]...
[*]child2.1[|]child2.2[|]child2.3[|]...
[*]child3.1[|]child3.2[|]child3.3[|]...
[*]...[|]...[|]...[|]...
[/table]
simple text
[table]
[**]a 1[||]and a 2[/**]
[*]A[|]B
[*]C[|]D
[/table]

[s]3, you're out[/s]
blah
BBCODE;

function BBTableToHTML($m) {
    return "<table class=\"ui compact stripet yellow table\">\n" .
           preg_replace_callback_array(
               [
                   '~\[\*\*]([^[]*(?:\[(?!/?\*\*])[^[]*)*)\[/\*\*]~' => 'BBTHeadToHTML',
                   '~(?:\[\*].*\R*)+~' => 'BBTBodyToHTML',
                   '~\[\*](.*)~' => 'BBTBodyRowToHTML'
               ],
               $m[1]
           ) .
           "</table>";
}

function BBTHeadToHTML($m) {
    return "\t<thead>\n" .
           "\t\t<tr>\n\t\t\t<th>" . str_replace('[||]', "</th>\n\t\t\t<th>", $m[1]) . "</th>\n\t\t</tr>\n" .
           "\t</thead>";
}

function BBTBodyToHTML($m) {
    return "\t<tbody>\n{$m[0]}\t</tbody>\n";
}

function BBTBodyRowToHTML($m) {
    return "\t\t<tr>\n\t\t\t<td>" . str_replace('[|]', "</td>\n\t\t\t<td>", $m[1]) . "</td>\n\t\t</tr>";
}

echo preg_replace_callback(
         '~\[table]\R*([^[]*(?:\[(?!/?table])[^[]*)*)\R*\[/table]~',
         'BBTableToHTML',
         $bbcode
     );

Output:

[b]Check out this demo[/b]
¯\_(ツ)_/¯
<table class="ui compact stripet yellow table">
    <thead>
        <tr>
            <th>header1</th>
            <th>header2</th>
            <th>header3</th>
            <th>...</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>child1.1</td>
            <td>child1.2</td>
            <td>child1.3</td>
            <td>...</td>
        </tr>
        <tr>
            <td>child2.1</td>
            <td>child2.2</td>
            <td>child2.3</td>
            <td>...</td>
        </tr>
        <tr>
            <td>child3.1</td>
            <td>child3.2</td>
            <td>child3.3</td>
            <td>...</td>
        </tr>
        <tr>
            <td>...</td>
            <td>...</td>
            <td>...</td>
            <td>...</td>
        </tr>
    </tbody>
</table>
simple text
<table class="ui compact stripet yellow table">
    <thead>
        <tr>
            <th>a 1</th>
            <th>and a 2</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>A</td>
            <td>B</td>
        </tr>
        <tr>
            <td>C</td>
            <td>D</td>
        </tr>
    </tbody>
</table>

[s]3, you're out[/s]
blah
mickmackusa
  • 43,625
  • 12
  • 83
  • 136