How can I replace spaces inside of HTML tags without removing the tags

Viewed 114

Let's say I have this string:

$string = '<p > ¡Esto es una prueba! < /p > <p> <strong > Prueba 123 </strong> </p> <p> <strong> < a href="https://matricom.net"> MATRICOM < / a> </ strong> </p> <p> <strong > Todas las pruebas aquí ... </strong > < /p>'

What I want to do is fix the HTML tags using PHP (they are malformed due to the spaces). I have tried several different regex expressions that I have found online such as this:

$html = trim(preg_replace('/<\s+>/', '<>', $text));

and:

$html = preg_replace('/<(.+?)(?:»| |″)(.+?)>/', '<\1\2>', $text);

I am attempting to get a string output like this (spaces removed in front part and end part of HTML tags):

'<p> ¡Esto es una prueba! </p> <p> <strong> Prueba 123 </strong> </p> <p> <strong> <a href="https://matricom.net"> MATRICOM </a> </strong> </p> <p> <strong> Todas las pruebas aquí ... </strong> </p>'

Backstory: Google Translate has the tendency to add random spaces in translation results which affect HTML structure. Just looking for a quick way to clean the tags up. I have been searching for two days how to do this and can't seem to find anything that fits quite what I'm looking for.

3 Answers

This is what I came up with. Works with your string

< *(\/*) *(.+?) *>

<     Matches a < char
 *    Matches zero or more spaces. There is a ' ' (space) before *
(\/*) Matches zero or more / () indicates capturing group 1
 *    Matches zero or more. Do notice the ' ' before *
(     Start of capturing group 2
.+    Matches any character except a line break
?     Lazy Matching
)     End of capturing group 2
 *   Matches zero or more spaces. Again a ' ' before *
>     Matches a > char

And then something like

$cleaned = preg_replace('/< *(\/*) *(.+?) *>/', '<\1\2>', $html);
echo $cleaned;

# input string
# '< p > ¡Esto es una prueba! < /p > <p> <strong > Prueba 123 </strong> </p> <p> <strong> < a href="https://matricom.net"> MATRICOM < / a> </ strong> </p> <p> <strong > Todas las pruebas aquí </strong > < /p>';

# Cleaned string
# <p> ¡Esto es una prueba! </p> <p> <strong> Prueba 123 </strong> </p> <p> <strong> <a href="https://matricom.net"> MATRICOM </a> </strong> </p> <p> <strong> Todas las pruebas aquí </strong> </p>

This will remove spaces from these formats

< div > </ div > < / div > < div class="myclass" >

But it will not remove spaces in the attributes. So this < div class = " myclass " > will be converted to <div class = " myclass ">. But spaces in attributes are allowed (even though not recommended)

If I have missed a case please let me know and I would try to incorporate the same.

You can use

preg_replace('~<\K\s*(?:(/)\s+)?|\s+(?=>)~u', '$1', $string)

See the regex demo and the PHP demo:

$string = '<p > ¡Esto es una prueba! < /p > <p> <strong > Prueba 123 </strong> </p> <p> <strong> < a href="https://matricom.net"> MATRICOM < / a> </ strong> </p> <p> <strong > Todas las pruebas aquí ... </strong > < /p>';

echo preg_replace('~<\K\s*(?:(/)\s+)?|\s+(?=>)~u', '$1', $string);
// => <p> ¡Esto es una prueba! </p> <p> <strong> Prueba 123 </strong> </p> <p> <strong> <a href="https://matricom.net"> MATRICOM </a> </strong> </p> <p> <strong> Todas las pruebas aquí ... </strong> </p>

Regex details:

  • <\K\s*(?:(/)\s+)? - < is matched and then dropped from the match with \K, then zero or more whitespaces are matched, then an optional sequence of / (captured into Group 1) and one or more whitespaces is matched
  • | - or
  • \s+(?=>) - one or more whitespaces that are immediately followed with >

The replacement is Group 1 value (it is either empty string or / when the optional group was matched).

I wouldn't recommend this approach. While regex are fantastic, you might miss some cases since it appears that Google Translates adds random spaces in random places. Your could would not be reliable for all cases.

I would suggest to either send the plain text or use the format=html parameter of the V2 Translate APIs to have Google Translate correctly interpret HTML tags.

https://cloud.google.com/translate/docs/reference/rest/v2/translate#query-parameters

If you can not use the above official method, split the text based on tags BEFORE sending it to Google Translate, so that you can have a much clearer input.

Related