<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jérémie G.</title>
    <description>The latest articles on DEV Community by Jérémie G. (@nazario).</description>
    <link>https://dev.to/nazario</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3550309%2Fa4202639-a5d0-4b22-80d1-bfab45557658.jpg</url>
      <title>DEV Community: Jérémie G.</title>
      <link>https://dev.to/nazario</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nazario"/>
    <language>en</language>
    <item>
      <title>There is no standard for bank CSV exports. Here's what that looks like in practice</title>
      <dc:creator>Jérémie G.</dc:creator>
      <pubDate>Thu, 08 Oct 2026 05:32:22 +0000</pubDate>
      <link>https://dev.to/nazario/there-is-no-standard-for-bank-csv-exports-heres-what-that-looks-like-in-practice-116n</link>
      <guid>https://dev.to/nazario/there-is-no-standard-for-bank-csv-exports-heres-what-that-looks-like-in-practice-116n</guid>
      <description>&lt;p&gt;I run &lt;a href="https://scancompte.com" rel="noopener noreferrer"&gt;ScanCompte&lt;/a&gt;, a small web app that turns an exported bank statement into a readable summary of where the money goes. Users upload a CSV from their bank. That sounds like the easy part, but it turned out to be the hardest.&lt;/p&gt;

&lt;p&gt;Before anyone mentions it: standard formats do exist (OFX, QIF, CAMT.053). But the "Export to CSV" button most people get in their online banking follows no standard. Every bank invents its own file, and sometimes one bank produces two different files depending on the account type.&lt;/p&gt;

&lt;p&gt;Here's what "no standard" looks like with French banks.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Encoding: a coin toss
&lt;/h2&gt;

&lt;p&gt;Some exports are UTF-8, many are Windows-1252, and some UTF-8 files start with a BOM that ends up glued to the first column name. So your code looks for &lt;code&gt;Date&lt;/code&gt; and finds &lt;code&gt;\xEF\xBB\xBFDate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When the encoding is wrong, "Prélèvement" becomes "PrÃ©lÃ¨vement", and any matching on labels fails without an error.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The separator: usually not a comma
&lt;/h2&gt;

&lt;p&gt;French numbers use a decimal comma (&lt;code&gt;1 234,56&lt;/code&gt;), so most banks separate columns with a semicolon. Most, not all. Don't assume the separator; detect it from the header line.&lt;/p&gt;

&lt;p&gt;A minimal reader covering points 1 and 2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;readBankCsv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;file_get_contents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;preg_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/^\xEF\xBB\xBF/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// strip BOM&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;mb_check_encoding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'UTF-8'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;mb_convert_encoding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'UTF-8'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Windows-1252'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$firstLine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;strtok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$delimiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$firstLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;';'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nb"&gt;substr_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$firstLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;';'&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;','&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nv"&gt;$stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'php://temp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r+'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$raw&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;rewind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;$row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;fgetcsv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$delimiter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'"'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$rows&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$row&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;fgetcsv&lt;/code&gt; on a stream rather than splitting on newlines, because a quoted label can contain a line break. Pass the escape argument explicitly: relying on its default is deprecated as of PHP 8.4.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. No common template
&lt;/h2&gt;

&lt;p&gt;This is the real problem. Once the file reads correctly, you still have to map it to one shape: date, label, signed amount. Each bank has its own:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headers&lt;/strong&gt;: &lt;code&gt;Date opération&lt;/code&gt;, &lt;code&gt;Date de valeur&lt;/code&gt;, &lt;code&gt;Date&lt;/code&gt;, &lt;code&gt;Libellé&lt;/code&gt;, &lt;code&gt;Libelle&lt;/code&gt;, &lt;code&gt;Détail&lt;/code&gt;, &lt;code&gt;Montant&lt;/code&gt;, &lt;code&gt;Débit&lt;/code&gt;, &lt;code&gt;Crédit&lt;/code&gt;...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amounts&lt;/strong&gt;: one signed column, or separate debit and credit columns where debits are sometimes positive. Thousands separators can be a space, a non-breaking space, or a dot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dates&lt;/strong&gt;: &lt;code&gt;DD/MM/YYYY&lt;/code&gt; most of the time, but not always.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preamble&lt;/strong&gt;: some files put account details above the real header row, so it isn't on line 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The approach that holds up is boring: find the header row by matching known column names, map columns through an alias list, and convert every amount to a signed integer number of cents before doing any maths.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Order and length aren't standard either
&lt;/h2&gt;

&lt;p&gt;Some banks export newest first, others oldest first. Length varies too: one user sends a month, another sends six years.&lt;/p&gt;

&lt;p&gt;My first version refused files over 100 lines. That was the worst step in the whole funnel. Nobody counts the lines of a CSV before exporting it, and the rejection came after they had done the work of exporting. Now the app keeps the header plus the first 300 transactions (about three months, enough for a monthly charge to show up three times) and tells the user before upload which part will be analysed. It counts the lines in the browser as soon as the file is picked.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. The export button is the first hurdle
&lt;/h2&gt;

&lt;p&gt;The CSV also has to exist. Some banks hide the export three menus deep, some only offer it on desktop, and some only offer PDF. Users get stuck before they ever see my app, so I ended up writing &lt;a href="https://scancompte.com/banks" rel="noopener noreferrer"&gt;one export guide per bank&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you're building something similar
&lt;/h2&gt;

&lt;p&gt;Collect real exports from as many banks as you can (anonymized), and test every change against all of them. Each bank has its own quirks, and real files catch more than reasoning about the format ever will.&lt;/p&gt;

&lt;p&gt;I'm curious: which file format has caused you the most trouble?&lt;/p&gt;

</description>
      <category>php</category>
      <category>csv</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Nouveaux outils IA découverts sur eXtragone</title>
      <dc:creator>Jérémie G.</dc:creator>
      <pubDate>Tue, 30 Dec 2025 21:16:10 +0000</pubDate>
      <link>https://dev.to/nazario/nouveaux-outils-ia-decouverts-sur-extragone-mc7</link>
      <guid>https://dev.to/nazario/nouveaux-outils-ia-decouverts-sur-extragone-mc7</guid>
      <description>&lt;p&gt;IA créative, productivité et qualité du code&lt;/p&gt;

&lt;p&gt;Je continue ma veille d'outils utiles, simples et efficaces. Voici une sélection récente ajoutée sur eXtragone, avec des usages concrets pour les créateurs et les développeurs.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎨 ImageToSketch
&lt;/h2&gt;

&lt;p&gt;Un outil IA qui transforme n'importe quelle photo en croquis ou dessin au trait.&lt;br&gt;
Aucun logiciel, aucun skill graphique requis. Tu importes une image, choisis un style et télécharges le rendu.&lt;br&gt;
Utile pour des visuels, avatars, illustrations ou idées créatives rapides.&lt;/p&gt;

&lt;h2&gt;
  
  
  📺 Thumbfa.st
&lt;/h2&gt;

&lt;p&gt;Un générateur de miniatures YouTube par IA pensé pour les créateurs de contenu.&lt;br&gt;
Tu importes tes photos, décris ta miniature ou donnes un exemple, et l'outil génère un visuel cohérent avec ton style.&lt;br&gt;
Gros gain de temps, surtout si tu publies régulièrement.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎧 TopMediai
&lt;/h2&gt;

&lt;p&gt;Plateforme IA tout-en-un pour la création multimédia.&lt;br&gt;
Musique générée à partir de texte ou d'images, voix-off réalistes, reprises vocales, génération vidéo, API disponibles.&lt;br&gt;
Clairement un couteau suisse pour automatiser ou enrichir des workflows créatifs.&lt;/p&gt;

&lt;h2&gt;
  
  
  🗓️ Paso
&lt;/h2&gt;

&lt;p&gt;Un planificateur minimaliste qui change la logique classique.&lt;br&gt;
Ici, on met en avant ce que tu as déjà accompli, pas juste ce qu'il reste à faire.&lt;br&gt;
Moins de pression, plus de clarté. Intéressant si tu cherches une approche plus saine de la productivité.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎵 MusicGPT
&lt;/h2&gt;

&lt;p&gt;Une plateforme très solide pour créer et éditer de la musique par IA.&lt;br&gt;
Beats, instrumentaux, voix, effets sonores, remix, amélioration audio.&lt;br&gt;
Web, mobile, API. Sans droits d'auteur. Très complet pour les projets audio et vidéo.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧑‍💻 Async Herald
&lt;/h2&gt;

&lt;p&gt;Un outil d'analyse de code GitHub pensé pour l'ère du vibecoding.&lt;br&gt;
Détection de failles de sécurité, anti-patterns, dette technique et problèmes classiques du code généré par IA.&lt;br&gt;
Rapide, lisible, peu cher. Franchement pertinent si tu utilises beaucoup l'IA pour coder.&lt;/p&gt;

&lt;p&gt;👉 Retrouve la selection complète et d'autres outils utiles sur eXtragone : &lt;a href="https://extrag.one" rel="noopener noreferrer"&gt;https://extrag.one&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>music</category>
      <category>socialmedia</category>
    </item>
    <item>
      <title>L'outil IA pour trouver un nom de projet rapidement</title>
      <dc:creator>Jérémie G.</dc:creator>
      <pubDate>Tue, 07 Oct 2025 04:46:38 +0000</pubDate>
      <link>https://dev.to/nazario/loutil-ia-pour-trouver-un-nom-de-projet-rapidement-1gfp</link>
      <guid>https://dev.to/nazario/loutil-ia-pour-trouver-un-nom-de-projet-rapidement-1gfp</guid>
      <description>&lt;h1&gt;
  
  
  Trouver le nom parfait pour ton projet (sans t’arracher les cheveux)
&lt;/h1&gt;

&lt;p&gt;Tu connais sûrement ce moment où tu veux lancer un nouveau projet, mais tu restes bloqué… sur &lt;strong&gt;le nom&lt;/strong&gt; 😅  &lt;/p&gt;

&lt;p&gt;Des heures à chercher des idées, à vérifier si le domaine est disponible, à constater que tout est déjà pris — et à finir par remettre ça au lendemain.&lt;/p&gt;

&lt;p&gt;J’ai voulu créer un petit outil pour simplifier tout ça.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Présentation de Nomi
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Nomi&lt;/strong&gt; est un générateur de noms de projet léger, pensé pour les développeurs et les créateurs qui veulent aller droit au but.  &lt;/p&gt;

&lt;p&gt;Il te propose une liste de noms, vérifie leur disponibilité en &lt;code&gt;.com&lt;/code&gt; et &lt;code&gt;.fr&lt;/code&gt;, et te permet d’exporter ou partager tes favoris (parfait pour brainstormer à plusieurs).&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Ce que tu peux faire avec Nomi
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;⚡ Générer une vingtaine de noms autour de ton idée.
&lt;/li&gt;
&lt;li&gt;🔍 Vérifier la disponibilité des domaines.
&lt;/li&gt;
&lt;li&gt;🤝 Partager tes favoris facilement pour décider en équipe.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;C’est &lt;strong&gt;gratuit&lt;/strong&gt;, &lt;strong&gt;sans inscription&lt;/strong&gt;, et disponible ici :&lt;br&gt;&lt;br&gt;
👉 &lt;a href="https://nomi.extrag.one" rel="noopener noreferrer"&gt;https://nomi.extrag.one&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Pourquoi j’ai créé Nomi
&lt;/h2&gt;

&lt;p&gt;En tant que dev, je lance souvent des projets personnels. Mais à chaque fois, je perds un temps fou à trouver un nom à la fois &lt;strong&gt;original&lt;/strong&gt;, &lt;strong&gt;disponible&lt;/strong&gt;, et &lt;strong&gt;mémorable&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;Je voulais une solution simple, avec un peu plus d’intelligence qu’un simple prompt d’IA.&lt;br&gt;&lt;br&gt;
Et surtout, quelque chose que je puisse utiliser rapidement à chaque nouvelle idée.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤖 Et en bonus…
&lt;/h2&gt;

&lt;p&gt;Le petit robot de Nomi est là pour t’accompagner pendant la recherche…&lt;br&gt;&lt;br&gt;
et franchement, il est plutôt mignon 😁  &lt;/p&gt;




&lt;p&gt;💬 Si tu testes l’outil, n’hésite pas à me dire ce que tu en penses ou à suggérer des idées d’amélioration !&lt;br&gt;&lt;br&gt;
Je serais curieux de voir quels noms il te propose 👀  &lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://nomi.extrag.one" rel="noopener noreferrer"&gt;Découvre Nomi ici&lt;/a&gt;&lt;/p&gt;

</description>
      <category>french</category>
    </item>
  </channel>
</rss>
