
_Créditos da imagem: ChatGPT
🚨 **CUIDADO COM REGEX NO PROTHEUS (TL++) – ISSO PODE DERRUBAR SEU SERVIDOR!** 🚨
Recentemente enfrentei um problema sério usando Regex no TL++ (linguagem do ERP TOTVS Protheus).
Estava desenvolvendo uma função para parsear URLs, servidores e paths. Usei Regex, afinal a linguagem oferece:
🔹 `Regex:Match()`
🔹 `Regex:Split()`
🔹 `Regex:Tokenizer()`
**Resultado?** 💥 **Desastre total.**
Bastou executar esta expressão:
```
"(?:(.*)://)?([^?/]*)(/[^?]*)?\??(.*)"
```
E…
🔥 CPU foi a 100%
🧠 Memória disparou
🐌 Threads ficaram presas
💣 Sem retorno, sem erro, apenas travamento
Testei também estas:
```
"(?:([^:@]*):?([^@:]*)@|)([^:]+):?(.*)"
"^((?:/.*/)|/)*(.*)$"
```
**Todas com o mesmo efeito: servidor colapsando.**
---
⚠️ **Por quê isso acontece?**
A engine de Regex do TL++ tem limitações severas:
❌ Não lida bem com backtracking
❌ Quantificadores `*`, `+`, `?` dentro de grupos destroem o desempenho
❌ Grupos opcionais e aninhados causam travamentos
O clássico problema de **Catastrophic Backtracking**, que leva ao consumo descontrolado de CPU e memória.
---
✅ **Solução prática:**
**Abandone regex no TL++ para esse tipo de processamento.**
Use parsing manual com:
🛠️ `At()`
🛠️ `SubStr()`
🛠️ `Left()`
🛠️ `Right()`
🛠️ `StrTokArr()`
---
🚀 **Exemplo real – Parseando uma URL sem Regex:**
```xBase
static function ParseURL(cUrl as character) as array
local cProtocolo:="" as character
local cHostPorta:="" as character
local cCaminho:="" as character
local cQuery:="" as character
local nPosPath as numeric
local nPosQuery as numeric
local nPosProto as numeric
// Protocolo
nPosProto:=AT("://",cUrl)
if (nPosProto>0)
cProtocolo:=Left(cUrl,nPosProto-1)
cUrl:=SubStr(cUrl,nPosProto+3)
endif
// HostPorta
nPosPath:=AT("/",cUrl)
nPosQuery:=AT("?",cUrl)
if (nPosPath>0)
cHostPorta:=Left(cUrl,nPosPath-1)
cUrl:=SubStr(cUrl,nPosPath)
elseif (nPosQuery>0)
cHostPorta:=Left(cUrl,nPosQuery-1)
cUrl:=SubStr(cUrl,nPosQuery)
else
cHostPorta:=cUrl
cUrl:=""
endif
// Caminho
if (Left(cUrl,1)=="/")
nPosQuery:=AT("?",cUrl)
if (nPosQuery>0)
cCaminho:=Left(cUrl,nPosQuery-1)
cUrl:=SubStr(cUrl,nPosQuery)
else
cCaminho:=cUrl
cUrl:=""
endif
endif
// Query
if (Left(cUrl,1)=="?")
cQuery:=SubStr(cUrl,2)
endif
return({cProtocolo,cHostPorta,cCaminho,cQuery})
```
💡 Simples, rápido, eficiente e seguro.
---
## ✅ Solução viável no SQL Server (ou qualquer banco relacional que suporte expressões regulares ou funções string):
### ✔️ SQL Server não tem suporte nativo a regex, mas você consegue obter os dados da URL de forma eficiente usando `STRING_SPLIT`, `CHARINDEX`, `SUBSTRING` e `PARSE` combinados.
### 🎯 Exemplo prático para a URL:
```sql
DECLARE @URL VARCHAR(500) = 'https://localhost:1234/webapp/?DEBUG=853000&E=Environment&P=U_410FSQL&M=1';
-- Quebrando a URL
WITH Parsed AS (
SELECT
-- Protocolo
CASE
WHEN CHARINDEX('://', @URL) > 0
THEN LEFT(@URL, CHARINDEX('://', @URL) - 1)
ELSE NULL
END AS Protocolo,
-- Host + Porta
CASE
WHEN CHARINDEX('://', @URL) > 0
THEN
SUBSTRING(
@URL,
CHARINDEX('://', @URL) + 3,
CHARINDEX('/', @URL + '/', CHARINDEX('://', @URL) + 3) - (CHARINDEX('://', @URL) + 3)
)
ELSE
LEFT(@URL, CHARINDEX('/', @URL + '/') - 1)
END AS HostPorta,
-- Caminho (Path)
CASE
WHEN CHARINDEX('/', @URL + '/', CHARINDEX('://', @URL) + 3) > 0
THEN
SUBSTRING(
@URL,
CHARINDEX('/', @URL + '/', CHARINDEX('://', @URL) + 3),
CHARINDEX('?', @URL + '?') - CHARINDEX('/', @URL + '/', CHARINDEX('://', @URL) + 3)
)
ELSE NULL
END AS Caminho,
-- QueryString
CASE
WHEN CHARINDEX('?', @URL) > 0
THEN RIGHT(@URL, LEN(@URL) - CHARINDEX('?', @URL))
ELSE NULL
END AS QueryString
)
SELECT * FROM Parsed;
```
### 🔥 Saída:
| Protocolo | HostPorta | Caminho | QueryString |
| --------- | -------------- | -------- | ---------------------------------------------- |
| https | localhost:1234 | /webapp/ | DEBUG=853000\&E=Environment\&P=U\_410FSQL\&M=1 |
---
## ✔️ Se quiser quebrar os parâmetros da QueryString em linhas no SQL:
```sql
DECLARE @QueryString VARCHAR(MAX) = 'DEBUG=853000&E=Environment&P=U_410FSQL&M=1';
SELECT
LTRIM(RTRIM(value)) AS ParametroValor
FROM STRING_SPLIT(@QueryString, '&');
```
### 🔸 Resultado:
| ParametroValor |
| -------------- |
| DEBUG=853000 |
| E=Environment |
| P=U\_410FSQL |
| M=1 |
Se quiser ainda quebrar chave e valor:
```sql
SELECT
LEFT(ParametroValor, CHARINDEX('=', ParametroValor) - 1) AS Parametro,
RIGHT(ParametroValor, LEN(ParametroValor) - CHARINDEX('=', ParametroValor)) AS Valor
FROM (
SELECT LTRIM(RTRIM(value)) AS ParametroValor
FROM STRING_SPLIT(@QueryString, '&')
) AS T
WHERE CHARINDEX('=', ParametroValor) > 0;
```
| Parametro | Valor |
| --------- | ----------- |
| DEBUG | 853000 |
| E | Environment |
| P | U\_410FSQL |
| M | 1 |
---
🧠 **Aprendizado:**
> Nem sempre a solução mais “bonita” (Regex) é a melhor.
> Conhecer as limitações da plataforma é papel de qualquer desenvolvedor profissional.
## 🚩 Conclusão
Sim, você consegue extrair os mesmos dados que a expressão regex tentava obter diretamente em AdvPL/TLPP ou no SQL, de forma bem mais performática e estável, **sem o risco de travar servidor Protheus ou aumentar uso de memória**.
---
👉 E você? Já passou por algo parecido no Protheus ou em outro sistema? Me conta aqui nos comentários. 👇
---
\#totvs #protheus #tlpp #regex #erp #desenvolvimento #devprotheus #programacao #desenvolvedores #tech #erpdevelopment #parsing #performancesoftware
---

Comentários
Postar um comentário