I think I found a bug in Lua string.patterns, can anyone help see if it's true ?

47 views
Skip to first unread message

Domingo Alvarez Duarte

unread,
5:31 AM (14 hours ago) 5:31 AM
to lua-l
While doing some text replacements I found an unexpected behavior that can be replicated with this Lua shown bellow, I've tested with Lua 5.1 through 5.5 and LuaJIT, maybe I'm missing something subtle here, any help is welcome.
====
local txt2 = [===[
03.01.411A01.22700      Limpieza y aseo                                              1.210.830,00                    0,00                 0,00                0,00          1.210.830,00        0,00         1.075.110,90       88,79         1.021.998,36       84,40          871.196,21       71,95          150.802,15         188.831,64




Cuentas Anuales. Ejercicio 2024                                                                                                                                                                                                                                                                                                    Pág. 64
                    CUENTAS ANUALES DE LA ADMINISTRACIÓN GENERAL DE LA COMUNIDAD DE CASTILLA Y LEÓN. EJERCICIO 2024


EJECUCIÓN DEL PRESUPUESTO DE GASTOS DEL EJERCICIO 2024
GASTOS POR APLICACIÓN
ADMINISTRACIÓN GENERAL                                                                                                                                                                                                                                                                          A FECHA DE 31/12/2024
                                     APLICACION                            PRESUPUESTO INICIAL        MODIFICACIONES       MODIFICACIONES           TOTAL            PRESUPUESTO          (2)/(1) %   COMPROMISOS (3)      (3)/(2) %    OBLIGACIONES        (4)/(2) %      PAGOS            (5)/(2) %   OBLIG.PTES PAGO      REMANENTES DE

                                                                                   (1)                  POSITIVAS            NEGATIVAS          MODIFICACIONES       DEFINITIVO (2)                                                    RECONOCIDAS (4)                  REALIZADOS (5)                                          CREDITO


03.01.411A01.22701      Seguridad                                                        493.750,00                 0,00                 0,00                 0,00          493.750,00         0,00            40.532,49        8,21            40.064,73        8,11           36.164,79        7,32            3.899,94          453.685,27


03.01.411A01.22703      Postales                                                           1.212,00                 0,00                 0,00                 0,00             1.212,00        0,00             1.208,23       99,69             1.208,23       99,69            1.208,23       99,69                0,00                 3,77


03.01.411A01.22704      Custodia, depósito y almacenaje.                                 219.293,00                 0,00                 0,00                 0,00          219.293,00         0,00             4.683,24        2,14             4.683,24        2,14            4.683,24        2,14                0,00          214.609,76


03.01.411A01.22706      Estudios y trabajos técnicos                                     257.392,00                 0,00                 0,00                 0,00          257.392,00         0,00           185.197,25       71,95           185.197,14       71,95          143.786,77       55,86           41.410,37           72.194,86

]===]

local remove_re = [==[



Cuentas Anuales%. Ejercicio %d+                                         +Pág%. %d+
                    CUENTAS ANUALES DE LA ADMINISTRACIÓN GENERAL DE LA COMUNIDAD DE CASTILLA Y LEÓN%. EJERCICIO %d+


EJECUCIÓN DEL PRESUPUESTO DE GASTOS DEL EJERCICIO %d+
GASTOS POR APLICACIÓN
ADMINISTRACIÓN GENERAL[^\n]*
[^\n]+

[^\n]+

]==]

txt2 = txt2:gsub(remove_re, "")
print(txt2)
====
I'm expecting this output:
====
03.01.411A01.22700      Limpieza y aseo                                              1.210.830,00                    0,00                 0,00                0,00          1.210.830,00        0,00         1.075.110,90       88,79         1.021.998,36       84,40          871.196,21       71,95          150.802,15         188.831,64


03.01.411A01.22701      Seguridad                                                        493.750,00                 0,00                 0,00                 0,00          493.750,00         0,00            40.532,49        8,21            40.064,73        8,11           36.164,79        7,32            3.899,94          453.685,27


03.01.411A01.22703      Postales                                                           1.212,00                 0,00                 0,00                 0,00             1.212,00        0,00             1.208,23       99,69             1.208,23       99,69            1.208,23       99,69                0,00                 3,77


03.01.411A01.22704      Custodia, depósito y almacenaje.                                 219.293,00                 0,00                 0,00                 0,00          219.293,00         0,00             4.683,24        2,14             4.683,24        2,14            4.683,24        2,14                0,00          214.609,76


03.01.411A01.22706      Estudios y trabajos técnicos                                     257.392,00                 0,00                 0,00                 0,00          257.392,00         0,00           185.197,25       71,95           185.197,14       71,95          143.786,77       55,86           41.410,37           72.194,86
====
but I'm getting this output:
====
03.01.411A01.22700      Limpieza y aseo                                              1.210.830,00                    0,00                 0,00                0,00          1.210.830,00        0,00         1.075.110,90       88,79         1.021.998,36       84,40          871.196,21       71,95          150.802,15         188.831,64

03.01.411A01.22704      Custodia, depósito y almacenaje.                                 219.293,00                 0,00                 0,00                 0,00          219.293,00         0,00             4.683,24        2,14             4.683,24        2,14            4.683,24        2,14                0,00          214.609,76


03.01.411A01.22706      Estudios y trabajos técnicos                                     257.392,00                 0,00                 0,00                 0,00          257.392,00         0,00           185.197,25       71,95           185.197,14       71,95          143.786,77       55,86           41.410,37           72.194,86
====
I've tested with pcre2 and javascript and I do get my expected output with this javascript:
====
const str = `
03.01.411A01.22700      Limpieza y aseo                                              1.210.830,00                    0,00                 0,00                0,00          1.210.830,00        0,00         1.075.110,90       88,79         1.021.998,36       84,40          871.196,21       71,95          150.802,15         188.831,64




Cuentas Anuales. Ejercicio 2024                                                                                                                                                                                                                                                                                                    Pág. 64
                    CUENTAS ANUALES DE LA ADMINISTRACIÓN GENERAL DE LA COMUNIDAD DE CASTILLA Y LEÓN. EJERCICIO 2024


EJECUCIÓN DEL PRESUPUESTO DE GASTOS DEL EJERCICIO 2024
GASTOS POR APLICACIÓN
ADMINISTRACIÓN GENERAL                                                                                                                                                                                                                                                                          A FECHA DE 31/12/2024
                                     APLICACION                            PRESUPUESTO INICIAL        MODIFICACIONES       MODIFICACIONES           TOTAL            PRESUPUESTO          (2)/(1) %   COMPROMISOS (3)      (3)/(2) %    OBLIGACIONES        (4)/(2) %      PAGOS            (5)/(2) %   OBLIG.PTES PAGO      REMANENTES DE

                                                                                   (1)                  POSITIVAS            NEGATIVAS          MODIFICACIONES       DEFINITIVO (2)                                                    RECONOCIDAS (4)                  REALIZADOS (5)                                          CREDITO


03.01.411A01.22701      Seguridad                                                        493.750,00                 0,00                 0,00                 0,00          493.750,00         0,00            40.532,49        8,21            40.064,73        8,11           36.164,79        7,32            3.899,94          453.685,27


03.01.411A01.22703      Postales                                                           1.212,00                 0,00                 0,00                 0,00             1.212,00        0,00             1.208,23       99,69             1.208,23       99,69            1.208,23       99,69                0,00                 3,77


03.01.411A01.22704      Custodia, depósito y almacenaje.                                 219.293,00                 0,00                 0,00                 0,00          219.293,00         0,00             4.683,24        2,14             4.683,24        2,14            4.683,24        2,14                0,00          214.609,76


03.01.411A01.22706      Estudios y trabajos técnicos                                     257.392,00                 0,00                 0,00                 0,00          257.392,00         0,00           185.197,25       71,95           185.197,14       71,95          143.786,77       55,86           41.410,37           72.194,86
`;

const regex = new RegExp(`


Cuentas Anuales\\. Ejercicio \\d+                                         +Pág\\. \\d+
                    CUENTAS ANUALES DE LA ADMINISTRACIÓN GENERAL DE LA COMUNIDAD DE CASTILLA Y LEÓN\\. EJERCICIO \\d+


EJECUCIÓN DEL PRESUPUESTO DE GASTOS DEL EJERCICIO \\d+
GASTOS POR APLICACIÓN
ADMINISTRACIÓN GENERAL[^\\n]*
[^\\n]+

[^\\n]+

`, 'g')

console.log(str.replaceAll(regex, ""));
====

Spar

unread,
7:50 AM (11 hours ago) 7:50 AM
to lua-l
It's hard to read. Perhaps, upload the code to pastebin or gist?
--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/lua-l/eeaad78a-27c0-4020-8f1c-dea4c5a604cdn%40googlegroups.com.

Domingo Alvarez Duarte

unread,
8:01 AM (11 hours ago) 8:01 AM
to lua-l

Luiz Henrique de Figueiredo

unread,
8:06 AM (11 hours ago) 8:06 AM
to lu...@googlegroups.com
> While doing some text replacements I found an unexpected behavior

What did you expect and how does it differ from what you got?

Domingo Alvarez Duarte

unread,
8:13 AM (11 hours ago) 8:13 AM
to lua-l

What I expect and what I've got is in the first message, the gist has one extra similar string that somehow get processed properly but the other don't.
I was expecting 5 non blank lines in the output but I'm getting only 3. 

Spar

unread,
8:16 AM (11 hours ago) 8:16 AM
to lua-l
A assume `[^\n]*` is what eating up half of the text.
 
* — Quantifier (zero or more). Allows to match the pattern zero or more times. This will match the longest sequence.
--

You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.

Domingo Alvarez Duarte

unread,
8:19 AM (11 hours ago) 8:19 AM
to lua-l
I agree with you that '[^\n]*` will match as much as possible but never anything with '\n'

Luiz Henrique de Figueiredo

unread,
8:20 AM (11 hours ago) 8:20 AM
to lu...@googlegroups.com
Try this simple pattern

local remove_re = "Cuentas Anuales.-CREDITO%s+"

Spar

unread,
8:21 AM (11 hours ago) 8:21 AM
to lu...@googlegroups.com
Correction. It's not actually the \n. It's because you used `[[ ]]` string literals which works as C++ raw literals. They don't accept escapes.
 
So what actually happens can be described by my tool which doesn't accept escapes too (i will fix it some day) :-)
 
On May 12, 2026 at 15:20 +0300, Luiz Henrique de Figueiredo <l...@tecgraf.puc-rio.br>, wrote:
Try this simple pattern

local remove_re = "Cuentas Anuales.-CREDITO%s+"

--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.

Domingo Alvarez Duarte

unread,
8:25 AM (11 hours ago) 8:25 AM
to lua-l
Yes I did tried that pattern and it produce the expected result, but I'm really interested in know why the original pattern is failing, because I'm using it in a multi thousand lines text and it does work fine in most of the cases but fail in some (like the one I put on the first message and the two I put on the gist https://gist.github.com/mingodad/4f54e0c26b66f72b21476cab6fa9fa47 where one succedd and the other fail).

Domingo Alvarez Duarte

unread,
8:35 AM (11 hours ago) 8:35 AM
to lua-l
Here is the pattern after `remove_re:gsub("\n", "\\n")` that I'm now looking at your tool:
====
\n\n\nCuentas Anuales%. Ejercicio %d+                                         +Pág%. %d+\n                     CUENTAS ANUALES DE LA ADMINISTRACIÓN GENERAL DE LA COMUNIDAD DE CASTILLA Y LEÓN%. EJERCICIO %d+\n\n\nEJECUCIÓN DEL PRESUPUESTO DE GASTOS DEL EJERCICIO %d+\nGASTOS POR APLICACIÓN\nADMINISTRACIÓN GENERAL[^\n]*\n[^\n]+\n\n[^\n]+\n\n
====

On Tuesday, May 12, 2026 at 2:21:24 PM UTC+2 Spar wrote:

Domingo Alvarez Duarte

unread,
8:39 AM (11 hours ago) 8:39 AM
to lua-l

Spar

unread,
8:41 AM (11 hours ago) 8:41 AM
to lua-l
That's what I said :)
Pretend like the input box is a [[ ]] literal.
 
YOu need to either use `"` literal for your pattern or gsub("\\n", "\n")

Domingo Alvarez Duarte

unread,
10:52 AM (8 hours ago) 10:52 AM
to lua-l
Thank you for all your feedback !
At the end it was my fault by expecting back slashed escaped chars to be valid inside long strings (a painful learning today).
I've added a Lua script that dumps a pattern and looks for false escaped chars and warn about then, it's in the same github gist here https://gist.github.com/mingodad/4f54e0c26b66f72b21476cab6fa9fa47  

Reply all
Reply to author
Forward
0 new messages