3

I have a regular expression to minify the result of the code generated by Laravel's view compiler. The regular expression does nothing more than minify the HTML when compiling a view. I'm having trouble setting the regex to ignore attributes starting with ":" and "@" (eg ... @click="hide(true)" :class="{collapsed: !open}">), since alpinejs uses them.

In the HTML code:

<select
                                        id="version-switcher"
                                        :class="{test: true}"
                                        aria-label="Localhost version"
                                        class="appearance-none"
                                        @change="window.location = $event.target.value"
                                    >
                                                                                    <option  value="https://localhost">Test</option>
                                                                                    <option selected value="https://localhost">Foo</option>
                                                                            </select>

The result should be:

<select id="version-switcher" :class="{test: true}" aria-label="Localhost version" class="appearance-none" @change="window.location = $event.target.value"><option value="https://localhost">Test</option><option selected value="https://localhost">Foo</option></select>

However, the output is:

<select id="version-switcher":class="{test: true}" aria-label="Localhost version" class="appearance-none"@change="window.location = $event.target.value"><option value="https://localhost">Test</option><option selected value="https://localhost">Foo</option></select>

Note that the attribute starting with : and the one starting with @ are not separate from the previous attribute. The regular expression is: return preg_replace('/<!--(.*?)-->|\s\B/um', '', $html);

Can someone help me with this problem please?

miken32
  • 42,008
  • 16
  • 111
  • 154

1 Answers1

1

You can use

preg_replace('~<!--[^-]*(?:-(?!->)[^-]*)*-->|\s+(?=\s[@:]?\w[\w-]*=|[<>])~u', '', $text)

See the regex demo.

Details:

  • <!--[^-]*(?:-(?!->)[^-]*)*--> - <!-- string, then zero or more chars other than -, then zero or more repetitions of - not immediately followed with -> and then zero or more non-hyphen chars
  • | - or
  • \s+ - one or more whitespaces
  • (?=\s[@:]?\w[\w-]*=|[<>]) - that are immediately followed with
    • \s[@:]?\w[\w-]*= - a whitespace, an optional @ or :, a word char, zero or more word or - chars and then a = char
    • | - or
    • [<>] - a < or > char.
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Excellent solution friend Wiktor Stribiżew! He had achieved the same result but differently and with multiple lines (which I don't like). My solution was: `$pattern = [ '/|\s\B/', '/<(.*?)>\s+/', '/([@:][a-zA-Z\d-]+=[\"\'][^\"\']*[\"\']\s*)/']; $replacement = [ '', '<$1>', ' $1$2'];`. Your solution is much simpler. Thank you! – Mauricio Mendoza May 04 '22 at 03:14
  • 1
    @MauricioMendoza Note that my regex part matching comments is written with the [unroll-the-loop principle](https://stackoverflow.com/a/39142688/3832970) so it is probably not that simple, but quite efficient. `\s\B` or `\s(?=\s)` is not correct as it removes spaces inside values, too, not just in between mark-up elements. – Wiktor Stribiżew May 04 '22 at 07:16