Question: How to escape multiple consecutive underscores in text literals?
I am using the standard Thymeleaf dialect for HTML (I am not using Spring or SpEL here).
In Thymeleaf, I can create an underscore as a text literal as follows:
<div th:text="'_'"></div>
This renders as:
<div>_</div>
I can create literals with 2 and 3 underscores in the same way:
<div th:text="'__'"></div>
<div th:text="'___'"></div>
But for 4 underscores, I get an error:
org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: ""
I assume (maybe incorrectly) this is because two pairs of underscores (__ followed by __) are the markers used by Thymeleaf for the expression preprocessor. And when these are removed, I am left with an empty expression - hence the error.
I can escape the underscores using the backslash (\) escape character. The following all give the required results:
<div th:text="'\_\___'"></div>
<div th:text="'\_\_\_\__'"></div>
<div th:text="'\_\_\_\___'"></div>
<div th:text="'_\_\_\_\___'"></div>
<div th:text="'\_\_\_\_\_\___'"></div>
But I can't just escape every underscore.
This displays a stray backslash:
<div th:text="'\_\_\_\_\_'"></div>
The result is:
<div>____\_</div>
So:
What are the rules for escaping underscores in text literals?
Is it really the preprocessor which is causing this behavior (inside text literals) - or is it something else?
Yeah, this is definitely part of the preprocessor.
It looks to me like the preprocessor only replaces an exact match of \_\_ with __. In any case where you have an odd number of \_'s, you will get the output \_ -- because it's not treating \_ as a real escape and instead only looking for \_\_.
I stumbled upon the same issue while providing underscore as placeholder for a code input field and found the following workarounds:
1. Insert zero width space as seperator
In the first example ('____') the zero witdh space is unescaped, but you can copy paste the string into your IDE of choice.
<div th:text="${'______'}"></div>
<div th:text="${'_​_​_​_​_​_'}"></div>
<div th:text="${'_​_​_​_​_​_'}"></div>
<div th:text="${'_​_​_​_​_​_'}"></div>
2. Use string replace
Surprisingly, this also seems to work. You can use any character, but no underscores in the original string, I chose "......". You can also use it with a string of unknown length by specifying a variable instead of a fixed string.
<div th:text="${#strings.replace('......', '.', '_')}"></div>
<div th:text="${#strings.replace('......', '.', '_')}"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With