From 6f362f41e7898e8868c6f09f21dca58d67d08030 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Wed, 27 Aug 2025 17:22:05 +0300 Subject: [PATCH] Backup: JSON optimization attempt with direct string merge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This version attempted to optimize JSON processing by: - Direct string concatenation without deserialization - MergeProductsJsonDirect and MergeOrdersJsonDirect functions - Direct STRTOFILE instead of nfJsonCreate Issues found: - Only 100 products saved instead of 812 (merge failed) - Invalid JSON syntax in orders: 'discounts':[, - Pattern matching errors for GoMag API structure Reverting to stable version 8324a26 next. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- gomag-vending-test.prg | 297 ++++++++++++++++++++++++++--------------- regex.prg | 268 +++++++++++++++++++++++++++++++++++++ 2 files changed, 458 insertions(+), 107 deletions(-) create mode 100644 regex.prg diff --git a/gomag-vending-test.prg b/gomag-vending-test.prg index c0c4d9b..212dc0b 100644 --- a/gomag-vending-test.prg +++ b/gomag-vending-test.prg @@ -28,9 +28,10 @@ SET DEFAULT TO (m.gcAppPath) lcPath = gcAppPath + 'nfjson;' SET PATH TO (m.lcPath) ADDITIVE -SET PROCEDURE TO nfjsonread.prg ADDITIVE SET PROCEDURE TO utils.prg ADDITIVE +SET PROCEDURE TO nfjsonread.prg ADDITIVE SET PROCEDURE TO nfjsoncreate.prg ADDITIVE +SET PROCEDURE TO regex.prg ADDITIVE *-- Initializare logging si statistici gnStartTime = SECONDS() @@ -108,11 +109,9 @@ ENDTRY IF llGetProducts LogMessage("[PRODUCTS] Starting product retrieval", "INFO", gcLogFile) - *-- Bucla pentru preluarea tuturor produselor (paginare) - loAllJsonData = CREATEOBJECT("Empty") - ADDPROPERTY(loAllJsonData, "products", CREATEOBJECT("Empty")) - ADDPROPERTY(loAllJsonData, "total", 0) - ADDPROPERTY(loAllJsonData, "pages", 0) + *-- Bucla pentru preluarea tuturor produselor (paginare) - optimizare JSON direct + LOCAL lcAllProductsJson + lcAllProductsJson = "" lnTotalProducts = 0 DO WHILE llHasMorePages @@ -147,28 +146,31 @@ IF llGetProducts *-- Success - preluare raspuns lcResponse = loHttp.ResponseText - *-- Parsare JSON cu nfjson - SET PATH TO nfjson ADDITIVE - loJsonData = nfJsonRead(lcResponse) - - IF !ISNULL(loJsonData) - *-- Prima pagina - setam informatiile generale - IF lnCurrentPage = 1 + *-- Optimizare: folosim JSON direct fara parsare completa + IF lnCurrentPage = 1 + *-- Prima pagina - parsam doar pentru metadata + SET PATH TO nfjson ADDITIVE + loJsonData = nfJsonRead(lcResponse) + + IF !ISNULL(loJsonData) IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N' - loAllJsonData.total = VAL(TRANSFORM(loJsonData.total)) + lnTotalProducts = VAL(TRANSFORM(loJsonData.total)) ENDIF IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' - loAllJsonData.pages = VAL(TRANSFORM(loJsonData.pages)) + lnTotalPages = VAL(TRANSFORM(loJsonData.pages)) ENDIF - LogMessage("[PRODUCTS] Total items: " + TRANSFORM(loAllJsonData.total) + " | Pages: " + TRANSFORM(loAllJsonData.pages), "INFO", gcLogFile) + LogMessage("[PRODUCTS] Total items: " + TRANSFORM(lnTotalProducts) + " | Pages: " + TRANSFORM(lnTotalPages), "INFO", gcLogFile) ENDIF - *-- Adaugare produse din pagina curenta - IF TYPE('loJsonData.products') = 'O' - DO MergeProducts WITH loAllJsonData, loJsonData - ENDIF + *-- Salvam JSON-ul complet pentru prima pagina + lcAllProductsJson = lcResponse + ELSE + *-- Paginile urmatoare - merge direct JSON + lcAllProductsJson = MergeProductsJsonDirect(lcAllProductsJson, lcResponse) + ENDIF - *-- Verificare daca mai sunt pagini + *-- Verificare daca mai sunt pagini + IF lnCurrentPage = 1 AND !ISNULL(loJsonData) IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' lnTotalPages = VAL(TRANSFORM(loJsonData.pages)) IF lnCurrentPage >= lnTotalPages @@ -180,14 +182,14 @@ IF llGetProducts llHasMorePages = .F. ENDIF ENDIF - - lnCurrentPage = lnCurrentPage + 1 - ELSE - *-- Eroare parsare JSON - LogMessage("[PRODUCTS] ERROR: JSON parsing failed for page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile) - llHasMorePages = .F. + *-- Pentru paginile urmatoare, verificam daca am ajuns la limita + IF lnTotalPages > 0 AND lnCurrentPage >= lnTotalPages + llHasMorePages = .F. + ENDIF ENDIF + + lnCurrentPage = lnCurrentPage + 1 ELSE *-- Eroare HTTP @@ -219,16 +221,12 @@ IF llGetProducts ENDDO - *-- Salvare array JSON cu toate produsele - IF !ISNULL(loAllJsonData) AND TYPE('loAllJsonData.products') = 'O' + *-- Salvare JSON direct (optimizat) + IF !EMPTY(lcAllProductsJson) lcJsonFileName = lcOutputDir + "\gomag_all_products_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" - DO SaveProductsArray WITH loAllJsonData, lcJsonFileName + STRTOFILE(lcAllProductsJson, lcJsonFileName) LogMessage("[PRODUCTS] JSON saved: " + lcJsonFileName, "INFO", gcLogFile) - *-- Calculam numarul de produse procesate - IF TYPE('loAllJsonData.products') = 'O' - lnPropCount = AMEMBERS(laProducts, loAllJsonData.products, 0) - gnProductsProcessed = lnPropCount - ENDIF + gnProductsProcessed = lnTotalProducts ENDIF ELSE @@ -239,13 +237,11 @@ ENDIF IF llGetOrders LogMessage("[ORDERS] Starting orders retrieval (last " + TRANSFORM(loSettings.OrderDaysBack) + " days from " + lcStartDateStr + ")", "INFO", gcLogFile) - *-- Reinitializare pentru comenzi + *-- Reinitializare pentru comenzi - optimizare JSON direct lnCurrentPage = 1 llHasMorePages = .T. - loAllOrderData = CREATEOBJECT("Empty") - ADDPROPERTY(loAllOrderData, "orders", CREATEOBJECT("Empty")) - ADDPROPERTY(loAllOrderData, "total", 0) - ADDPROPERTY(loAllOrderData, "pages", 0) + LOCAL lcAllOrdersJson + lcAllOrdersJson = "" *-- Bucla pentru preluarea comenzilor DO WHILE llHasMorePages @@ -280,93 +276,63 @@ DO WHILE llHasMorePages *-- Success - preluare raspuns lcResponse = loHttp.ResponseText - *-- Parsare JSON cu nfjson - SET PATH TO nfjson ADDITIVE - loJsonData = nfJsonRead(lcResponse) - - IF !ISNULL(loJsonData) - *-- Debug: Afisam structura JSON pentru prima pagina - IF lnCurrentPage = 1 + *-- Optimizare: folosim JSON direct pentru comenzi + IF lnCurrentPage = 1 + *-- Prima pagina - parsam doar pentru metadata si salvam JSON-ul complet + loJsonData = nfJsonRead(lcResponse) + + IF !ISNULL(loJsonData) LogMessage("[ORDERS] DEBUG: Analyzing JSON structure...", "DEBUG", gcLogFile) lnPropCount = AMEMBERS(laJsonProps, loJsonData, 0) - FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) && Primele 10 proprietati + FOR lnDebugIndex = 1 TO MIN(lnPropCount, 10) lcPropName = laJsonProps(lnDebugIndex) lcPropType = TYPE('loJsonData.' + lcPropName) LogMessage("[ORDERS] Property: " + lcPropName + " (Type: " + lcPropType + ")", "DEBUG", gcLogFile) ENDFOR - ENDIF - - *-- Prima pagina - setam informatiile generale - IF lnCurrentPage = 1 + + LOCAL lnTotalOrders IF TYPE('loJsonData.total') = 'C' OR TYPE('loJsonData.total') = 'N' - loAllOrderData.total = VAL(TRANSFORM(loJsonData.total)) + lnTotalOrders = VAL(TRANSFORM(loJsonData.total)) ENDIF IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' - loAllOrderData.pages = VAL(TRANSFORM(loJsonData.pages)) + lnTotalPages = VAL(TRANSFORM(loJsonData.pages)) ENDIF - LogMessage("[ORDERS] Total items: " + TRANSFORM(loAllOrderData.total) + " | Pages: " + TRANSFORM(loAllOrderData.pages), "INFO", gcLogFile) - ENDIF - - *-- Adaugare comenzi din pagina curenta - *-- API-ul GoMag returneaza un array direct de comenzi - LOCAL llHasOrders, lnOrdersFound - llHasOrders = .F. - lnOrdersFound = 0 - - *-- Verificam daca JSON-ul contine proprietatea orders - IF TYPE('loJsonData.orders') = 'O' - *-- Numaram comenzile din obiectul orders - LOCAL ARRAY laOrdersProps[1] - LOCAL lnOrdersCount - lnOrdersCount = AMEMBERS(laOrdersProps, loJsonData.orders, 0) + LogMessage("[ORDERS] Total items: " + TRANSFORM(lnTotalOrders) + " | Pages: " + TRANSFORM(lnTotalPages), "INFO", gcLogFile) - IF lnOrdersCount > 0 - DO MergeOrdersArray WITH loAllOrderData, loJsonData - llHasOrders = .T. - lnOrdersFound = lnOrdersCount - LogMessage("[ORDERS] Found " + TRANSFORM(lnOrdersCount) + " orders in page " + TRANSFORM(lnCurrentPage), "INFO", gcLogFile) - gnOrdersProcessed = gnOrdersProcessed + lnOrdersCount - ENDIF - ELSE - *-- JSON-ul este direct un array de comenzi (backup logic) - lnDirectProps = AMEMBERS(laDirectProps, loJsonData, 0) - IF lnDirectProps > 0 - *-- Cream un obiect temporar cu structura asteptata - LOCAL loTempData - loTempData = CREATEOBJECT("Empty") - ADDPROPERTY(loTempData, "orders", loJsonData) - DO MergeOrdersArray WITH loAllOrderData, loTempData - llHasOrders = .T. - lnOrdersFound = lnDirectProps - LogMessage("[ORDERS] Found " + TRANSFORM(lnDirectProps) + " orders in page " + TRANSFORM(lnCurrentPage), "INFO", gcLogFile) - gnOrdersProcessed = gnOrdersProcessed + lnDirectProps + *-- Calculam comenzile din prima pagina + LOCAL lnFirstPageOrders + lnFirstPageOrders = 0 + IF TYPE('loJsonData.orders') = 'O' + lnFirstPageOrders = AMEMBERS(laTemp, loJsonData.orders, 0) ENDIF + gnOrdersProcessed = gnOrdersProcessed + lnFirstPageOrders ENDIF - IF !llHasOrders - LogMessage("[ORDERS] WARNING: No orders found in JSON response for page " + TRANSFORM(lnCurrentPage), "WARN", gcLogFile) - ENDIF + *-- Salvam JSON-ul complet pentru prima pagina + lcAllOrdersJson = lcResponse + ELSE + *-- Paginile urmatoare - merge direct JSON + lcAllOrdersJson = MergeOrdersJsonDirect(lcAllOrdersJson, lcResponse) + *-- Estimare comenzi procesate din dimensiunea JSON-ului + gnOrdersProcessed = gnOrdersProcessed + INT(LEN(lcResponse) / 500) + ENDIF - *-- Verificare daca mai sunt pagini + *-- Verificare daca mai sunt pagini + IF lnCurrentPage = 1 AND !ISNULL(loJsonData) IF TYPE('loJsonData.pages') = 'C' OR TYPE('loJsonData.pages') = 'N' lnTotalPages = VAL(TRANSFORM(loJsonData.pages)) IF lnCurrentPage >= lnTotalPages llHasMorePages = .F. ENDIF - ELSE - *-- Daca nu avem info despre pagini, verificam daca sunt comenzi - IF !llHasOrders - llHasMorePages = .F. - ENDIF ENDIF - - lnCurrentPage = lnCurrentPage + 1 - ELSE - *-- Eroare parsare JSON pentru comenzi - LogMessage("[ORDERS] ERROR: JSON parsing failed for page " + TRANSFORM(lnCurrentPage), "ERROR", gcLogFile) - llHasMorePages = .F. + *-- Pentru paginile urmatoare, verificam daca am ajuns la limita + IF lnTotalPages > 0 AND lnCurrentPage >= lnTotalPages + llHasMorePages = .F. + ENDIF ENDIF + + lnCurrentPage = lnCurrentPage + 1 ELSE *-- Eroare HTTP pentru comenzi @@ -398,10 +364,10 @@ DO WHILE llHasMorePages ENDDO - *-- Salvare array JSON cu toate comenzile - IF !ISNULL(loAllOrderData) AND TYPE('loAllOrderData.orders') = 'O' + *-- Salvare JSON direct (optimizat) + IF !EMPTY(lcAllOrdersJson) lcOrderJsonFileName = lcOutputDir + "\gomag_orders_last7days_" + DTOS(DATE()) + "_" + STRTRAN(TIME(), ":", "") + ".json" - DO SaveOrdersArray WITH loAllOrderData, lcOrderJsonFileName + STRTOFILE(lcAllOrdersJson, lcOrderJsonFileName) LogMessage("[ORDERS] JSON saved: " + lcOrderJsonFileName, "INFO", gcLogFile) ENDIF @@ -549,6 +515,123 @@ ENDIF ENDPROC +*-- Functie optimizata pentru merge direct JSON produse (fara deserializare) +PROCEDURE MergeProductsJsonDirect +PARAMETERS tcFirstPageJson, tcNextPageJson + +LOCAL lcEndPos, lcStart, lcEnd, lcNewProperties, lcResult + +*-- Gaseste sfârÈ™itul secÈ›iunii products din prima pagina - cautam pozitia } inainte de "total" +lcEndPos = AT('},\"total\"', tcFirstPageJson) + +IF lcEndPos = 0 + *-- Fallback: gaseste ultimul } inainte de total + lcEndPos = AT('\"total\"', tcFirstPageJson) + IF lcEndPos > 0 + lcEndPos = RAT('}', LEFT(tcFirstPageJson, lcEndPos - 1)) + ENDIF +ENDIF + +IF lcEndPos = 0 + *-- Nu putem face merge, returnam prima pagina + RETURN tcFirstPageJson +ENDIF + +*-- Debug logging pentru debugging +LogMessage("[PRODUCTS] DEBUG: Starting merge - Page 1 size: " + TRANSFORM(LEN(tcFirstPageJson)) + " | Next page size: " + TRANSFORM(LEN(tcNextPageJson)), "DEBUG", gcLogFile) +LogMessage("[PRODUCTS] DEBUG: Products end position found at: " + TRANSFORM(lcEndPos), "DEBUG", gcLogFile) + +*-- Daca nu putem extrage cu regex, incercam metoda manuala +lcStart = AT('\"products\":{', tcNextPageJson) +IF lcStart > 0 + lcStart = lcStart + 11 && dupa {"products":{ + lcEnd = AT('},\"total\"', tcNextPageJson) + IF lcEnd = 0 + lcEnd = AT('\"total\"', tcNextPageJson) + IF lcEnd > 0 + lcEnd = RAT('}', LEFT(tcNextPageJson, lcEnd - 1)) + ENDIF + ENDIF + + IF lcEnd > lcStart + lcNewProperties = SUBSTR(tcNextPageJson, lcStart, lcEnd - lcStart) + LogMessage("[PRODUCTS] DEBUG: Extracted " + TRANSFORM(LEN(lcNewProperties)) + " chars from next page", "DEBUG", gcLogFile) + + *-- Insereaza proprietatile cu virgula separator + lcResult = STUFF(tcFirstPageJson, lcEndPos, 0, ',' + lcNewProperties) + LogMessage("[PRODUCTS] DEBUG: Merge successful, result size: " + TRANSFORM(LEN(lcResult)), "DEBUG", gcLogFile) + RETURN lcResult + ELSE + LogMessage("[PRODUCTS] ERROR: Invalid extraction positions - Start: " + TRANSFORM(lcStart) + ", End: " + TRANSFORM(lcEnd), "ERROR", gcLogFile) + ENDIF +ENDIF + +*-- Daca nu putem extrage, returnam prima pagina +RETURN tcFirstPageJson + +ENDPROC + +*-- Functie optimizata pentru merge direct JSON comenzi (fara deserializare) +PROCEDURE MergeOrdersJsonDirect +PARAMETERS tcFirstPageJson, tcNextPageJson + +LOCAL lcEndPos, lcStart, lcEnd, lcNewOrders, lcResult +LOCAL lcTotalPos + +*-- Debug logging pentru debugging +LogMessage("[ORDERS] DEBUG: Starting merge - Page 1 size: " + TRANSFORM(LEN(tcFirstPageJson)) + " | Next page size: " + TRANSFORM(LEN(tcNextPageJson)), "DEBUG", gcLogFile) + +*-- Cautam pozitia pentru inserare inainte de "total", "page" sau "pages" +lcEndPos = AT('},\"total\"', tcFirstPageJson) +IF lcEndPos = 0 + lcEndPos = AT('},\"page\"', tcFirstPageJson) +ENDIF +IF lcEndPos = 0 + lcEndPos = AT('},\"pages\"', tcFirstPageJson) +ENDIF + +IF lcEndPos = 0 + LogMessage("[ORDERS] ERROR: Cannot find orders end position in first page", "ERROR", gcLogFile) + RETURN tcFirstPageJson +ENDIF + +LogMessage("[ORDERS] DEBUG: Orders end position found at: " + TRANSFORM(lcEndPos), "DEBUG", gcLogFile) + +*-- Extrage doar continutul din "orders":{...} din pagina urmatoare +lcStart = AT('\"orders\":{', tcNextPageJson) +IF lcStart > 0 + lcStart = lcStart + 10 && dupa {"orders":{ + + *-- Gaseste sfarsitul obiectului orders din pagina urmatoare + lcEnd = AT('},\"total\"', tcNextPageJson) + IF lcEnd = 0 + lcEnd = AT('},\"page\"', tcNextPageJson) + ENDIF + IF lcEnd = 0 + lcEnd = AT('},\"pages\"', tcNextPageJson) + ENDIF + + IF lcEnd > lcStart + lcNewOrders = SUBSTR(tcNextPageJson, lcStart, lcEnd - lcStart) + LogMessage("[ORDERS] DEBUG: Extracted " + TRANSFORM(LEN(lcNewOrders)) + " chars from next page", "DEBUG", gcLogFile) + + *-- Curatam orice } de la final daca exista + lcNewOrders = RTRIM(lcNewOrders, ' }') + + *-- Insereaza noile comenzi cu virgula + lcResult = STUFF(tcFirstPageJson, lcEndPos, 0, ',' + lcNewOrders) + LogMessage("[ORDERS] DEBUG: Merge successful, result size: " + TRANSFORM(LEN(lcResult)), "DEBUG", gcLogFile) + RETURN lcResult + ELSE + LogMessage("[ORDERS] ERROR: Invalid extraction positions - Start: " + TRANSFORM(lcStart) + ", End: " + TRANSFORM(lcEnd), "ERROR", gcLogFile) + ENDIF +ENDIF + +*-- Daca nu putem extrage, returnam prima pagina +RETURN tcFirstPageJson + +ENDPROC + *-- Functiile utilitare au fost mutate in utils.prg *-- Scriptul cu paginare completa pentru preluarea tuturor produselor si comenzilor diff --git a/regex.prg b/regex.prg new file mode 100644 index 0000000..272ca2e --- /dev/null +++ b/regex.prg @@ -0,0 +1,268 @@ +*!* CLEAR +*!* ?strtranx([ana are 1234567890.1234 lei], [\s\d+\.\d\s], [=TRANSFORM($1, "999 999 999 999.99")]) +*?strtranx([ana are <<1234567890.1234>> lei], [<<], [=TRANSFORM($1, "AA")]) +*!* RETURN +CLEAR + + +*-- http://www.cornerstonenw.com/article_id_parsing3.htm +SET STEP ON + +lcSourceString = [ana are mere 123,345 678 ad] +LOCAL laItems[10] + +lnResults = GetRegExpAll(lcSourceString, '\d+', @laItems) + +SET STEP ON +RETURN +strTest = [ab cd2""$$£] +?strTest +?StripNonAscii(strTest) + +*-- replace non a-z09 with "" case-insensitive +? strtranx([Ab ra /ca\d&abr'a],"[^a-z0-9]",[],1,,1) +RETURN + +*-- count words +? OccursRegExp("\b(\w+)\b", [the then quick quick brown fox fox]) +&& prints 7 + +*-- count repeatedwords +? OccursRegExp("\b(\w+)\s\1\b", [the then quick quick brown fox fox]) +&& prints 2 + + +*-- replace first and second lower-case "a" +? strtranx([Abracadabra],[a],[*],1,2) +&& prints Abr*c*dabra + +*-- replace first and second "a" case-insensitive +? strtranx([Abracadabra],[a],[*],1,2,1) +&& prints *br*cadabra + +*-- locate the replacement targets +? strtranx([Abracadabra],[^a|a$],[*],1,2,0) +&& Abracadabr* +? strtranx([Abracadabra],[^a|a$],[*],1,2,1) +&& *bracadabr* + + +lcText = "The cost, is $123,345.75. " +*-- convert the commas +lcText = strtranx( m.lcText, "(\d{1,3})\,(\d{1,}) ","$1 $2" ) + +*-- convert the decimals +? strtranx( m.lcText, "(\d{1,3})\.(\d{1,})", "$1,$2" ) + +** prints "The cost, is $123 345,75." + +*-- add 1 to all digits +? strtranx( [ABC123], "(\d)", [=TRANSFORM(VAL($1)+1)] ) +** prints "ABC234" + +*-- convert all dates to long format +? strtranx( [the date is: 7/18/2004 ] , [(\d{1,2}/\d{1,2}/\d{4})], [=TRANSFORM(CTOD($1),"@YL")]) +** prints "the date is: Sunday, July 18, 2004" + + +*---------------------------------------------------------- +FUNCTION StrtranRegExp( tcSourceString, tcPattern, tcReplace ) + LOCAL loRE + loRE = CREATEOBJECT("vbscript.regexp") + WITH loRE + .PATTERN = tcPattern + .GLOBAL = .T. + .multiline = .T. + RETURN .REPLACE( tcSourceString , tcReplace ) + ENDWITH +ENDFUNC + +*---------------------------------------------------------- +FUNCTION OccursRegExp(tcPattern, tcText) + LOCAL loRE, loMatches, lnResult + loRE = CREATEOBJECT("vbscript.regexp") + WITH loRE + .PATTERN = m.tcPattern + .GLOBAL = .T. + .multiline = .T. + loMatches = loRE.Execute( m.tcText ) + lnResult = loMatches.COUNT + loMatches = NULL + ENDWITH + RETURN m.lnResult +ENDFUNC + + + +*---------------------------------------------------------- +FUNCTION strtranx(tcSearched, ; + tcSearchFor, ; + tcReplacement, ; + tnStart, tnNumber, ; + tnFlag ) + + *-- the final version of the UDF + LOCAL loRE, lcText, lnShift, lcCommand,; + loMatch, loMatches, lnI, lnK, lcSubMatch,; + llevaluate, lcMatchDelim, lcReplaceText, lcReplacement,; + lnStart, lnNumber, loCol, lcKey + + IF EMPTY(NVL(tcSearched, '')) + RETURN NVL(tcSearched, '') + ENDIF + + loRE = CREATEOBJECT("vbscript.regexp") + + WITH loRE + .PATTERN = m.tcSearchFor + .GLOBAL = .T. + .multiline = .T. + .ignorecase = IIF(VARTYPE(m.tnFlag)=[N],m.tnFlag = 1,.F.) + ENDWITH + + lcReplacement = m.tcReplacement + + *--- are we evaluating? + IF m.lcReplacement = [=] + llevaluate = .T. + lcReplacement = SUBSTR( m.lcReplacement, 2 ) + ENDIF + + IF VARTYPE( m.tnStart )=[N] + lnStart = m.tnStart + ELSE + lnStart = 1 + ENDIF + + IF VARTYPE( m.tnNumber) =[N] + lnNumber = m.tnNumber + ELSE + lnNumber = -1 + ENDIF + + IF m.lnStart>1 OR m.lnNumber#-1 OR m.llevaluate + + lcText = m.tcSearched + lnShift = 1 + loMatches = loRE.execute( m.lcText ) + loCol = CREATEOBJECT([collection]) + lnNumber = IIF( lnNumber=-1,loMatches.COUNT,MIN(lnNumber,loMatches.COUNT)) + + FOR lnK = m.lnStart TO m.lnNumber + loMatch = loMatches.ITEM(m.lnK-1) && zero based + lcCommand = m.lcReplacement + FOR lnI= 1 TO loMatch.submatches.COUNT + lcSubMatch = loMatch.submatches(m.lnI-1) && zero based + IF m.llevaluate + * "escape" the string we are about to use in an evaluation. + * it is important to escape due to possible delim chars (like ", ' etc) + * malicious content, or VFP line-length violations. + lcKey = ALLTRIM(TRANSFORM(m.lnK)+[_]+TRANSFORM(m.lnI)) + loCol.ADD( m.lcSubMatch, m.lcKey ) + lcSubMatch = [loCol.item(']+m.lcKey+[')] + ENDIF + lcCommand = STRTRAN( m.lcCommand, "$" + ALLTRIM( STR( m.lnI ) ) , m.lcSubMatch) + ENDFOR + + IF m.llevaluate + TRY + lcReplaceText = EVALUATE( m.lcCommand ) + CATCH TO loErr + lcReplaceText="[[ERROR #"+TRANSFORM(loErr.ERRORNO)+[ ]+loErr.MESSAGE+"]]" + ENDTRY + ELSE + lcReplaceText = m.lcCommand + ENDIF + lcText = STUFF( m.lcText, loMatch.FirstIndex + m.lnShift, m.loMatch.LENGTH, m.lcReplaceText ) + lnShift = m.lnShift + LEN( m.lcReplaceText ) - m.loMatch.LENGTH + ENDFOR + ELSE + lcText = loRE.REPLACE( m.tcSearched, m.tcReplacement ) + ENDIF + RETURN m.lcText +ENDFUNC + +*===================== +FUNCTION StripNonAscii + LPARAMETERS tcSourceString, tcReplaceString + +TEXT TO lcPattern NOSHOW +[^A-Za-z 0-9 \.,\?'""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~] +ENDTEXT + lcReplace = IIF(TYPE('tcReplaceString') <> 'C', "", tcReplaceString) + lcReturn = strtranx( m.tcSourceString, m.lcPattern, m.lcReplace,1,,1) + + RETURN m.lcReturn +ENDFUNC && StripNonAscii + +*===================== +* Intoarce un text care se potriveste cu pattern-ul +* Ex. Localitatea din textul: STRADA NR LOCALITATE +*===================== +FUNCTION GetRegExp + LPARAMETERS tcSourceString, tcPattern, tnOccurence + + * tcSourceString: Bld. Stefan cel Mare 14 Tirgu Neamt + * tcPattern: [A-Za-z\s]+$ = (caracter sau spatiu) de cel putin o data la sfarsitul liniei = Tirgu Neamt + * tcPattern: \d+[A-Za-z\s]+$ = oricate cifre (caracter sau spatiu) de cel putin o data la sfarsitul liniei = 14 Tirgu Neamt + + LOCAL loRE, loMatches, lcResult, lnOccurence + lcResult = '' + lnOccurence = IIF(!EMPTY(m.tnOccurence) and TYPE('tnOccurence') = 'N', m.tnOccurence, 1) + + loRE = CREATEOBJECT("vbscript.regexp") + WITH loRE + .PATTERN = m.tcPattern + .GLOBAL = .T. + .multiline = .T. + loMatches = loRE.Execute( m.tcSourceString) + IF loMatches.COUNT >= m.lnOccurence + lcResult = loMatches.Item(m.lnOccurence - 1).Value + ENDIF + loMatches = NULL + ENDWITH + + RETURN m.lcResult +ENDFUNC && GetRegExp + +*===================== +* Intoarce numarul potrivirilor si un parametru OUT array sau lista de numere facturi separate prin "," +* Ex. Toate numerele dintr-un text lnMatches = GetRegExpAll(lcSourceString, '\d+', @loMatches) +*===================== +FUNCTION GetRegExpAll + LPARAMETERS tcSourceString, tcPattern, taItems + + * tcSourceString: Bld. Stefan cel Mare 14 Tirgu Neamt + * tcPattern: [A-Za-z\s]+$ = (caracter sau spatiu) de cel putin o data la sfarsitul liniei = Tirgu Neamt + * tcPattern: \d+[A-Za-z\s]+$ = oricate cifre (caracter sau spatiu) de cel putin o data la sfarsitul liniei = 14 Tirgu Neamt + * taItems "A">taItems : array cu rezultatele (OUT) taItems[1..Result] sau taItems "C" lista facturi separate prin virgula + LOCAL loRE, loMatches, lnResults, lnItem + IF TYPE('taItems') = "A" + EXTERNAL ARRAY taItems + ELSE + taItems = "" + ENDIF + lnResult = 0 + + loRE = CREATEOBJECT("vbscript.regexp") + WITH loRE + .PATTERN = m.tcPattern + .GLOBAL = .T. + .multiline = .T. + loMatches = loRE.Execute( m.tcSourceString) + lnResults = loMatches.COUNT + IF TYPE('taItems') = "A" + DIMENSION taItems[m.lnResult] + FOR lnItem = 1 TO m.lnResult + taItems[m.lnItem] = loMatches.Item(m.lnItem-1).Value + ENDFOR + ELSE + FOR lnItem = 1 TO m.lnResults + taItems = taItems + IIF(m.lnItem > 1, ",", "") + loMatches.Item(m.lnItem-1).Value + ENDFOR + ENDIF + loMatches = NULL + ENDWITH + + RETURN m.lnResults +ENDFUNC && GetRegExp \ No newline at end of file