Profiles / Programming
SE

String & encoding developer

Cleaning, case styles, regex, URL/HTML/Base64 encodings, number bases and encryption.

10 recipes on this page · open in the interactive view

Recipes
  1. Clean a customer line before import
  2. SQL table and API names from form labels
  3. Parse an API access log line
  4. Encode a payment callback and check it
  5. Colors, permissions and character codes
  6. Encrypt, decrypt and sign a secret
  7. Match a typed product name to the catalog
  8. Mail merge: fill a template from JSON data
  9. Mask personal data before writing a log line
  10. Write and read a fixed width bank transfer file
executed on MentDB

Clean a customer line before import

A customer file arrives with extra spaces, mixed case, accents and an empty note. The script trims and normalises each field, builds the initials, a padded customer code and a slug, and outputs a clean CSV line.

Pipeline
Script
admin
#1. A raw line of a customer file with spaces, accents and mixed case;
-> "[name]" "  jean-PAUL    dupont-lefèvre ";
-> "[mail]" " ÉLODIE.Martin@Mail.COM  ";
-> "[city]" "   Saint-Denis   ";
-> "[country]" " FRANCE ";
-> "[code]" "  042  ";
-> "[note]" "";
#2. Clean every field;
-> "[name]" (string capitalize_words (string itrim (string lrtrim [name])));
-> "[mail]" (string lcase (string unaccent (string trim [mail])));
-> "[city]" (string upper (string rtrim (string ltrim [city])));
-> "[code]" (concat "C" (string lpad (string lrtrim [code]) "0" 6));
-> "[initials]" (concat (string ucase (string first_letter [name])) (string upper (string first_letter (string mid [name] (+ (string instr [name] " ") 1)))));
#3. Optional field, slug and CSV export;
-> "[note]" (string empty_if_null (string null_if_empty [note]));
concat (string csv_value [code] ";" "\"") ";" (string csv_value [name] ";" "\"") ";" [initials] ";" [mail] ";" [city] ";" (string first_letter_upper (string lower (string trim [country]))) ";" (string slugify [name]) ";" (string zero [note]) ";blank=" (string is_blank [note]) ";" (string lrtrim0 "00042")
Result
mentdb
C000042;Jean-Paul Dupont-Lefèvre;JD;elodie.martin@mail.com;SAINT-DENIS;France;jean-paul-dupont-lefevre;0;blank=1;42
Go further
executed on MentDB

SQL table and API names from form labels

A form has French labels with accents and spaces. The script turns them into snake_case column names aligned with padding, SQL comments with escaped quotes, a camelCase JSON field, a kebab-case route and an HTML view of the MQL snippet for the wiki.

Pipeline
Script
admin
#1. Business labels of a form become a SQL table;
-> "[labels]" "Date de naissance,Montant TTC,Numéro client,Commentaire libre du vendeur";
-> "[ddl]" (concat "CREATE TABLE " (string snake_case "Fiche Client") " (" [_n_]);
-> "[i]" 0;
#2. One column per label: snake_case name, padded for alignment, SQL comment;
for (-> "[i]" 1) (<= [i] 4) (++ "[i]") {
  -> "[lab]" (atom get [labels] [i] ",");
  -> "[col]" (string snake_case (string unaccent [lab]));
  -> "[ddl]" (concat [ddl] (string rpad [col] " " 30) "VARCHAR(100) COMMENT " (string txt2 (string truncate [lab] 20)) "," [_n_]);
};
-> "[ddl]" (concat (string substring [ddl] 0 (- (string length [ddl]) 2)) [_n_] ");");
#3. Same names for the JSON API and the URL routes, plus the snippet in HTML for the wiki;
concat (string indent [ddl] 2) [_n_] (string repeat "-" 40) [_n_] "json: " (string camel_case (string unaccent "Montant TTC")) ", route: /" (string kebab_case (string camel_case (string unaccent "Numéro client"))) [_n_] "sql literals: " (string to_string "O\"Neil") " " (string txt "l'été") [_n_] "trimmed: " (string sublrchar "[ok]" 1) (string space 2) (string replace "v1.2.3" "." "_") [_n_] (string del_char_before_each_line (concat "-- col1" [_n_] "-- col2") 3) [_n_] "doc html: " (string mql_to_html (mql {string snake_case "Fiche Client";}))
Result
mentdb
CREATE TABLE fiche_client (
  date_de_naissance             VARCHAR(100) COMMENT 'Date de naissance',
  montant_ttc                   VARCHAR(100) COMMENT 'Montant TTC',
  numero_client                 VARCHAR(100) COMMENT 'Numéro client',
  commentaire_libre_du_vendeur  VARCHAR(100) COMMENT 'Commentaire libre...'
  );
----------------------------------------
json: montantTtc, route: /numero-client
sql literals: 'O"Neil' 'l\'été'
trimmed: ok  v1_2_3
col1
col2

doc html: <span style='color:#00baff'>string</span> <span style='color:#00baff'>snake_case</span> <span style='color:#fff'>"Fiche Client"</span>;
Go further
  • Pick the column types with the type is_* checks on sample data
  • string truncate keeps comments under the database limit
executed on MentDB

Parse an API access log line

An access log line holds a date, a level, a route with an order id, a status and a duration. The script extracts the fields with regex groups, rewrites the date, reads the variables of an error message with a pattern and classifies the line with the match functions.

Pipeline
Script
admin
#1. One line of an API access log;
-> "[l]" "2026-11-01 08:15:42 ERROR [api] GET /orders/A-1234?user=jim 500 812ms";
#2. Extract the fields with regex groups;
-> "[code]" (string regexp_extract [l] " ([0-9]{3}) [0-9]+ms$" 1);
-> "[ms]" (string regexp_extract [l] "([0-9]+)ms$" 1);
-> "[order]" (string regexp_extract [l] "/orders/([A-Z]-[0-9]+)" 1);
-> "[day]" (string regexp_replace (string left [l] 10) "([0-9]+)-([0-9]+)-([0-9]+)" "$3/$2/$1");
-> "[msg]" "Timeout in module payment at line 42";
-> "[vars]" (string replace (string replace (string get_variable [msg] "[1] in module [2] at line [3]") [_n_] "") "  " "");
#3. Classify the line;
-> "[words]" (string split [l] " " -1);
concat "{\"day\": \"" [day] "\", \"order\": \"" [order] "\", \"status\": " [code] ", \"ms\": " [ms] ", \"message_vars\": " [vars] ", \"words\": " [words] ", \"numbers\": " (string regexp_count [l] "[0-9]+") ", \"slashes\": " (string count [l] "/") ", \"is_error\": " (string contains [l] "ERROR") ", \"has_user\": " (string contains_ignore_case [l] "USER=") ", \"api_tag\": " (string regexp [l] ".*\[api\].*") ", \"not_debug\": " (string not_regexp [l] ".*DEBUG.*") ", \"like_get\": " (string like [l] ".* GET .*") ", \"not_like_post\": " (string not_like [l] ".* POST .*") ", \"matches\": " (string matches [l] ".*orders.*") ", \"is_matches_regex\": " (type is_matches_regex [l] ".*812ms") ", \"starts_2026\": " (string starts_with [l] "2026") ", \"starts_digit\": " (string starts_with_or [l] "0123456789") ", \"ends_ms\": " (string ends_with [l] "ms") ", \"level_is_error\": " (string equals_ignore_case (string split_mql [l] 2) "error") ", \"parts\": " (string split_sentence "GET /orders/A-1234?user=jim" "/?=") "}"
Result
mentdb
{"day": "01/11/2026", "order": "A-1234", "status": 500, "ms": 812, "message_vars": ["Timeout","payment","42"], "words": ["2026-11-01","08:15:42","ERROR","[api]","GET","\/orders\/A-1234?user=jim","500","812ms"], "numbers": 9, "slashes": 2, "is_error": 1, "has_user": 1, "api_tag": 1, "not_debug": 1, "like_get": 1, "not_like_post": 1, "matches": 1, "is_matches_regex": 1, "starts_2026": 1, "starts_digit": 1, "ends_ms": 1, "level_is_error": 1, "parts": ["GET","orders","A-1234","user","jim"]}
Go further
executed on MentDB

Encode a payment callback and check it

A payment callback carries a French label with & and accents, a Basic auth header and an HTML note. The script URL-encodes and Base64-encodes them, escapes for HTML and JSON, decodes everything back and measures the label.

Pipeline
Script
admin
#1. A payment callback with a French label and an HTML note;
-> "[label]" "Commande n°42 & frais d'été";
-> "[q]" (concat "label=" (string url_encode [label]) "&amount=19.90");
-> "[auth]" (concat "Basic " (string encode_b64 "shop:test-key"));
#2. Safe versions for HTML and JSON outputs;
-> "[html]" (string html_escape "<b>Tom & Jerry's</b>");
-> "[js]" (string json_escape (concat "line1" [_n_] "say \"hi\""));
#3. Decode everything back and measure the label;
concat "{\"query\": \"" [q] "\", \"auth\": \"" [auth] "\", \"auth_back\": \"" (string decode_b64 (string mid [auth] 6)) "\", \"label_back\": \"" (string url_decode (string mid [q] 6 (string instr [q] "&a"))) "\", \"html\": \"" [html] "\", \"html_back\": \"" (string html_unescape "caf&#233; &amp; th&#xE9;") "\", \"json_value\": \"" [js] "\", \"utf8_to_latin1\": \"" (string encode "abc" "UTF-8" "ISO-8859-1") "\", \"length\": " (string length [label]) ", \"char_length\": " (string char_length [label]) ", \"bit_length\": " (string bit_length [label]) "}"
Result
mentdb
{"query": "label=Commande%20n%C2%B042%20%26%20frais%20d%27%C3%A9t%C3%A9&amount=19.90", "auth": "Basic c2hvcDp0ZXN0LWtleQ==", "auth_back": "shop:test-key", "label_back": "Commande n°42 & frais d'été", "html": "&lt;b&gt;Tom &amp; Jerry&#39;s&lt;/b&gt;", "html_back": "café & thé", "json_value": "line1\nsay \"hi\"", "utf8_to_latin1": "abc", "length": 27, "char_length": 27, "bit_length": 216}
Go further
executed on MentDB

Colors, permissions and character codes

A front developer needs the RGB values of the brand color #FFB547 and a sysadmin wants to read the 755 permission in decimal and in bits. The script converts between hexadecimal, octal, binary and characters.

Pipeline
Script
admin
#1. A web color and a Unix permission to decode;
-> "[color]" "FFB547";
-> "[r]" (string hex_to_int (string left [color] 2));
-> "[g]" (string unhex (string mid [color] 2 4));
-> "[b]" (string hex_to_int (string right [color] 2));
-> "[perm]" (string oct_to_int "755");
#2. Characters and their codes;
-> "[c]" "é";
concat "{\"rgb\": [" [r] ", " [g] ", " [b] "], \"back_to_hex\": \"" (string upper (concat (string hex [r]) (string int_to_hex [g]) (string int_to_hex [b]))) "\", \"perm_755_decimal\": " [perm] ", \"perm_bits\": \"" (string bin [perm]) "\", \"perm_octal\": \"" (string oct [perm]) "|" (string int_to_oct 420) "\", \"ascii_A\": " (string ascii "A") ", \"code_e_acute\": " (string char_to_int [c]) ", \"char_77\": \"" (string char 77) (string int_to_char 68) (string int_to_char 66) "\", \"hex_of_MDB\": \"" (string str_to_hex "MDB") "\", \"hex_41_to_str\": \"" (string hex_to_str "41") "\"}"
Result
mentdb
{"rgb": [255, 181, 71], "back_to_hex": "FFB547", "perm_755_decimal": 493, "perm_bits": "111101101", "perm_octal": "755|644", "ascii_A": 65, "code_e_acute": 233, "char_77": "MDB", "hex_of_MDB": "4d4442", "hex_41_to_str": "A"}
Go further
executed on MentDB

Encrypt, decrypt and sign a secret

An API token must be stored encrypted and its origin proven. The script generates RSA and signature key pairs, encrypts the token with RSA, DES, Blowfish and PBE, decrypts each one, signs it and checks that a tampered token fails the signature.

Pipeline
Script
admin
#1. Key pairs for RSA and for signatures, kept as JSON in memory;
json load "rx_rsa" (string encode_rsa_generate_keypair "2048");
json load "rx_sig" (string encode_sign_generate_keypair "2048");
-> "[secret]" (concat "token-" (string uuid));
#2. Encrypt with RSA, DES, Blowfish and PBE, then decrypt;
-> "[rsa]" (string encode_rsa [secret] (json select "rx_rsa" "/publicKey") (json select "rx_rsa" "/privateKey"));
-> "[des_key]" (string encode_des_generate_key "56");
-> "[des]" (string encode_des [secret] [des_key]);
-> "[bf]" (string encode_blowfish [secret] "vault-key-2026");
-> "[pbe]" (string encode_pbe [secret] "master-password");
#3. Sign the secret and check the signature;
-> "[sig]" (string encode_sign [secret] (json select "rx_sig" "/privateKey"));
-> "[ok]" (concat "{\"rsa_ok\": " (string equals_ignore_case (string decode_rsa [rsa] (json select "rx_rsa" "/privateKey")) [secret]) ", \"des_ok\": " (string equals_ignore_case (string decode_des [des] [des_key]) [secret]) ", \"blowfish_ok\": " (string equals_ignore_case (string decode_blowfish [bf] "vault-key-2026") [secret]) ", \"pbe_ok\": " (string equals_ignore_case (string decode_pbe [pbe] "master-password") [secret]) ", \"signature_ok\": " (string decode_sign_verify [secret] [sig] (json select "rx_sig" "/publicKey")) ", \"tampered_ok\": " (string decode_sign_verify (concat [secret] "x") [sig] (json select "rx_sig" "/publicKey")) ", \"random_salt_length\": " (string length (string generate_random_str 16)) "}");
json unload "rx_rsa";
json unload "rx_sig";
[ok]
Result
mentdb
{"rsa_ok": 1, "des_ok": 1, "blowfish_ok": 1, "pbe_ok": 1, "signature_ok": 1, "tampered_ok": 0, "random_salt_length": 16}
Go further
  • Keep the private keys out of the code: read them from a parameter
  • For passwords, prefer string bcrypt_hash, which cannot be decrypted
executed on MentDB

Match a typed product name to the catalog

A user types a product name with small differences from the catalog. The script measures the edit distance and the sentence distance, picks the best catalog label, then cuts the SKU into family and variant and checks its parts.

Pipeline
Script
admin
#1. A product name typed by a user, to match against the catalog;
-> "[typed]" "Ecran 27 pouces IPS";
-> "[ref]" "SKU-EC27-IPS";
#2. Edit distance and sentence distance to the catalog labels;
-> "[lev]" (string levenshtein_distance (string lower "Ecran 27p IPS") (string lower "ecran 27 ips"));
-> "[sd]" (string sentence_distance 40 70 [typed] "Ecran IPS 27 pouces noir");
-> "[best]" (string sentences_distance 40 70 [typed] "{\"1\": {\"i\": \"Clavier sans fil\", \"o\": \"SKU-KB01\"}, \"2\": {\"i\": \"Ecran IPS 27 pouces\", \"o\": \"SKU-EC27-IPS\"}, \"3\": {\"i\": \"Ecran 24 pouces TN\", \"o\": \"SKU-EC24-TN\"}}");
-> "[sku]" (json load select "rx_best" [best] "/best_predict");
json unload "rx_best";
#3. Cut the SKU into its parts;
-> "[p1]" (string instr [ref] "-");
-> "[p2]" (string locate [ref] "-" (+ [p1] 1));
concat "{\"levenshtein\": " [lev] ", \"sentence_distance\": " [sd] ", \"best_sku\": \"" [sku] "\", \"family\": \"" (string substr [ref] (+ [p1] 1) [p2]) "\", \"variant\": \"" (string substring [ref] (+ [p2] 1)) "\", \"prefix\": \"" (string left [ref] 3) "\", \"suffix\": \"" (string right [ref] 3) "\", \"dash_pos\": [" (string position [ref] "-") ", " (string strpos [ref] "-" 4) "], \"sorted\": " (string order "[\"SKU-EC27-IPS\", \"SKU-EC24-TN\", \"SKU-KB01\"]") ", \"cmp\": " (string strcmp "SKU-EC24-TN" "SKU-EC27-IPS") ", \"reversed\": \"" (string reverse [ref]) "\", \"grouped\": \"" (string repeat_insert_str "4111111111111111" " " 4) "\", \"letters_only\": " (string is_letter "Ecran") ", \"alnum\": " (string is_alpha_num "EC27") ", \"alnum_uds\": " (string is_alpha_num_uds "EC_27") ", \"digits\": " (string is_number_char "27") "}"
Result
mentdb
{"levenshtein": 1, "sentence_distance": 200.0, "best_sku": "SKU-EC27-IPS", "family": "EC27", "variant": "IPS", "prefix": "SKU", "suffix": "IPS", "dash_pos": [3, 8], "sorted": ["SKU-EC24-TN","SKU-EC27-IPS","SKU-KB01"], "cmp": -3, "reversed": "SPI-72CE-UKS", "grouped": "4111 1111 1111 1111 ", "letters_only": 1, "alnum": 1, "alnum_uds": 1, "digits": 1}
Go further
executed on MentDB

Mail merge: fill a template from JSON data

Fill the {{placeholders}} of a shipping mail with the data of an order: values are first formatted the French way (capital first letter, 1 249,50 with a thousands space, dd/MM/yyyy), then merged with a loop on the JSON fields. Unresolved placeholders are counted and removed, and the text is produced in plain and in safe HTML.

Pipeline
Script
admin
#1. A mail template with placeholders and the data of one customer;
-> "[tpl]" "Hello {{first_name}},|your order {{order}} of {{amount}} EUR ships on {{ship_date}}.|Track it: {{track_url}}|{{missing}}";
json load "rx_p4l_data" "{\"first_name\": \"élodie\", \"order\": \"A-1042\", \"amount\": 1249.5, \"ship_date\": \"2026-11-03\", \"track_url\": \"https://track.example.com/?id=A-1042&lang=fr\"}";
#2. Format the values the French way before the merge: 1 249,50 and dd/MM/yyyy;
json uobject "rx_p4l_data" "/" "first_name" (string first_letter_upper (json select "rx_p4l_data" "/first_name")) STR;
-> "[amt]" (json select "rx_p4l_data" "/amount");
-> "[int]" (string trim (string reverse (string repeat_insert_str (string reverse (math trunc [amt])) " " 3)));
-> "[cents]" (string lpad (math round (* (math frac_part [amt]) 100) 0) "0" 2);
json uobject "rx_p4l_data" "/" "amount" (concat [int] "," [cents]) STR;
json uobject "rx_p4l_data" "/" "ship_date" (date format (json select "rx_p4l_data" "/ship_date") "yyyy-MM-dd" "dd/MM/yyyy") STR;
#3. Replace each placeholder by its value;
-> "[text]" [tpl];
json parse_obj "rx_p4l_data" "/" "[k]" "[v]" {
	-> "[text]" (string replace [text] (concat "{{" [k] "}}") [v]);
};
json unload "rx_p4l_data";
#4. Placeholders without data are listed then removed;
-> "[left]" (string regexp_count [text] "\{\{[a-z_]+\}\}");
-> "[name]" (string regexp_extract [text] "\{\{([a-z_]+)\}\}" 1);
-> "[text]" (string regexp_replace [text] "\|?\{\{[a-z_]+\}\}" "");
#5. Plain text for the SMS, HTML for the mail;
-> "[plain]" (string replace [text] "|" [_n_]);
-> "[html]" (concat "<p>" (string replace (string html_escape [text]) "|" "<br>") "</p>");
concat [plain] [_n_] "--- " (string length [plain]) " chars, unresolved: " [left] " (" [name] ")" [_n_] [html];
Result
mentdb
Hello Élodie,
your order A-1042 of 1 249,50 EUR ships on 03/11/2026.
Track it: https://track.example.com/?id=A-1042&lang=fr
--- 123 chars, unresolved: 1 (missing)
<p>Hello Élodie,<br>your order A-1042 of 1 249,50 EUR ships on 03/11/2026.<br>Track it: https://track.example.com/?id=A-1042&amp;lang=fr</p>
Go further
  • Keep the templates in a node or in translate set keys to have one version per language.
  • Send the HTML with mail send once the text has no {{ left.
executed on MentDB

Mask personal data before writing a log line

A support log line contains an e-mail, a card number, an IBAN, a phone, an IP and an API token. The script masks each one with the rule of its kind (PCI DSS keeps the last 4 digits of a card), redacts the secret and replaces the user by a stable salted pseudonym.

Pipeline
Script
admin
#1. A support log line full of personal data, before it goes to the shared logs;
-> "[line]" "2026-11-01 09:12 user=marie.dupont@gmail.com card=4970 1012 3456 7890 iban=FR7630006000011234567890189 tel=+33 6 12 34 56 78 ip=192.168.1.42 token=sk_live_9f8e7d6c5b4a";
#2. E-mail: keep the first letter and the domain;
-> "[mail]" (string regexp_extract [line] "user=([^ ]+)" 1);
-> "[mail_m]" (concat (string left [mail] 1) (string repeat "*" (- (string instr [mail] "@") 1)) (string substring [mail] (string instr [mail] "@")));
#3. Card: only the last 4 digits, the PCI DSS rule;
-> "[card]" (string regexp_replace (string regexp_extract [line] "card=([0-9 ]{19})" 1) " " "");
-> "[card_m]" (string repeat_insert_str (concat (string repeat "*" 12) (string right [card] 4)) " " 4);
#4. IBAN, phone, IP and secret with regular expressions;
-> "[out]" (string replace [line] [mail] [mail_m]);
-> "[out]" (string regexp_replace [out] "card=[0-9 ]{19}" (concat "card=" (string trim [card_m])));
-> "[out]" (string regexp_replace [out] "(FR[0-9]{2})[0-9]{19}([0-9]{4})" "$1*******************$2");
-> "[out]" (string regexp_replace [out] "(\+33 [0-9]) [0-9]{2} [0-9]{2} [0-9]{2} ([0-9]{2})" "$1 ** ** ** $2");
-> "[out]" (string regexp_replace [out] "ip=([0-9]+\.[0-9]+)\.[0-9]+\.[0-9]+" "ip=$1.x.x");
-> "[out]" (string regexp_replace [out] "token=[A-Za-z0-9_]+" "token=[REDACTED]");
#5. A stable pseudonym lets support follow the same user without the e-mail;
-> "[pseudo]" (concat "usr_" (string left (string sha_256 (concat "salt-2026:" (string lower [mail]))) 10));
concat [out] [_n_] "pseudonym: " [pseudo] [_n_] "digits left in clear: " (string regexp_count [out] "[0-9]") " of " (string regexp_count [line] "[0-9]") ", e-mail kept: " (string contains [out] [mail]) ", same length: " (== (string length (string trim [card_m])) 19);
Result
mentdb
2026-11-01 09:12 user=m***********@gmail.com card=**** **** **** 7890 iban=FR76*******************0189 tel=+33 6 ** ** ** 78 ip=192.168.x.x token=[REDACTED]
pseudonym: usr_a8895a160d
digits left in clear: 33 of 79, e-mail kept: 0, same length: 1
Go further
  • Put the masking in an exe script and include it in every log write of your services.
  • Store the salt in a private parameter (parameter set_private) rather than in the code.
executed on MentDB

Write and read a fixed width bank transfer file

Build a fixed width transfer file for a bank: detail records with a sequence number, a name in upper case without accents cut or padded to 24 characters, an 11-digit account and the amount in cents on 12 digits, then a trailer with the count and the control total, and an MD5 checksum. The bank side reads the fields back by position and checks the total.

Pipeline
Script
admin
#1. Transfers to send to the bank in a fixed width file: type 2, name 24, account 11, amount 12 in cents;
-> "[rows]" "Hélène Côté-Dubois;00012345678;1250.5|Jean Martin;98765432100;89.99|Société Réunionnaise des Eaux Tropicales;55511122233;14000";
-> "[file]" "";
-> "[total]" 0;
for (-> "[i]" 1) (<= [i] (atom size [rows] "|")) (++ "[i]") {
	-> "[r]" (atom get [rows] [i] "|");
	#2. Banks want upper case without accents, cut or padded to the width;
	-> "[name]" (string rpad (string left (string upper (string unaccent (atom get [r] 1 ";"))) 24) " " 24);
	-> "[cents]" (math round (* (atom get [r] 3 ";") 100) 0);
	-> "[total]" (+ [total] [cents]);
	-> "[file]" (concat [file] "02" (string lpad [i] "0" 6) [name] (atom get [r] 2 ";") (string lpad [cents] "0" 12) [_n_]);
};
#3. Trailer record with the count and the control total, then a checksum;
-> "[file]" (concat [file] "09" (string lpad (atom size [rows] "|") "0" 6) (string space 35) (string lpad [total] "0" 12));
-> "[md5]" (string md5 [file]);
#4. The bank side: read the fields back by position and check the total;
-> "[check]" 0;
-> "[parsed]" "";
for (-> "[j]" 1) (< [j] (atom size [file] [_n_])) (++ "[j]") {
	-> "[l]" (atom get [file] [j] [_n_]);
	-> "[amount]" (/ (string substring [l] 43 55) 100);
	-> "[check]" (+ [check] (string substring [l] 43 55));
	-> "[parsed]" (concat [parsed] (string rtrim (string substring [l] 8 32)) " | " (string substring [l] 32 43) " | " [amount] [_n_]);
};
-> "[trailer]" (atom get_last [file] [_n_]);
concat [file] [_n_] "--- every line " (string length [trailer]) " chars, md5 " [md5] [_n_] [parsed] "control total: " (string lrtrim0 (string right [trailer] 12)) " cents, recomputed: " [check] ", equal: " (== [check] (string right [trailer] 12));
Result
mentdb
02000001HELENE COTE-DUBOIS      00012345678000000125050
02000002JEAN MARTIN             98765432100000000008999
02000003SOCIETE REUNIONNAISE DES55511122233000001400000
09000003                                   000001534049
--- every line 55 chars, md5 b9294a861c1315974513bbdc5990d59e
HELENE COTE-DUBOIS | 00012345678 | 1250.5
JEAN MARTIN | 98765432100 | 89.99
SOCIETE REUNIONNAISE DES | 55511122233 | 14000
control total: 1534049 cents, recomputed: 1534049, equal: 1
Go further
  • Write the file with file create "tmp/..." and send it with sftp put in a job.
  • Real bank formats (CFONB 160, AFB 120) only change the widths and the record types.

Also in Programming

MB
MQL beginner
Variables, operators, if, loops and your first try/exception: learn MQL step by step.
10 recipes
MD
MQL developer
Atom lists, data types, constants, translations, session variables and error patterns.
10 recipes
BW
Backend & web service developer
Typed scripts, execute / call / include, generated calls and URLs, parameters and logs.
10 recipes
DT
Date & time developer
Calendars, business days, time zones, ISO and epoch, durations, quarters and week numbers.
10 recipes
DV
Data validation developer
IBAN, BIC, SIRET, Luhn, email, IP, UUID, JSON and date checks gathered in a validation report.
10 recipes
JD
JSON & document store developer
In-memory JSON documents, persistent nodes and sequences: build, walk, sort, clean up.
10 recipes
SD
Script developer
Full script lifecycle in the MQL editor: typed parameters, read back, generate, patch, deploy, copy, grant, delete.
10 recipes
EM
Execution modes
execute, call, include, sub_include, parallel, stack: which environment, which checks, which logs.
11 recipes
WS
Web service developer
A small REST resource with get, post, put and delete scripts: validation, JSON answers, codes, grants, URLs and API docs.
10 recipes
AD
Async developer
Asynchronous processing with the stack: push runs now or later, priorities and parallel limits, errors and replays, flows and cleanup.
10 recipes
SD
Scheduler developer
Cron jobs and delayed runs: add, resume, pause, update and remove jobs, prove they ran, and postpone stack runs with a delay condition.
10 recipes
ED
Event developer
Event-driven scripts: file watchers that push each file event to the stack, validation, archiving, errors and safe restarts.
10 recipes
CC
Configuration & connections
Parameters (private, described, locked, deployed), environment variables, sessions and connections used by your scripts.
12 recipes
VD
Versioning & deployment
Group your scripts, commit, compare, roll back, export, import and package a release.
10 recipes
DE
Debugging & error handling
Coded errors with try/exception, logs with correlation ids, timing, metrics and defensive checks.
10 recipes
SD
SQL developer in MQL
Connections, DDL and DML with sql encode, transactions, cursors, parse, and exports to JSON, CSV, Excel and PDF on a real local database. Run the recipes in order: the first one creates the tuto_db_h2 database.
10 recipes
CD
CRUD & data API developer
Generate SCRUD scripts from a table, patch and install them, write typed read and write APIs, check data quality and manage connections per environment. Uses the tuto_db_h2 database of the SQL developer recipes; the last recipe removes it.
10 recipes
WA
Web application developer
Create a web app, its host name, pages, ajax forms, menu and grants, then remove it all.
10 recipes
AI
Algorithms in MQL
Sorting, searching, recursion, data structures and number algorithms: MQL is a real programming language.
10 recipes
CF
Control flow
if, if force, case, switch, mode, for, while, repeat, break, continue, parallel and synchronized on real cases.
10 recipes
TM
The MQL language in depth
Data types and null, booleans, comments, variables and scope, eval and mql blocks, coded errors and try.
10 recipes
SU
Screen & UI developer (sajax)
Build the screens of MentDB web apps in MQL: Bootstrap grids, forms and every control, ajax buttons, alerts, refreshes and charts.
10 recipes