{"id":373,"date":"2026-04-26T15:09:12","date_gmt":"2026-04-26T13:09:12","guid":{"rendered":"https:\/\/huguesg.fr\/site\/?page_id=373"},"modified":"2026-04-26T15:16:12","modified_gmt":"2026-04-26T13:16:12","slug":"les-finances-de-sncf-reseau","status":"publish","type":"page","link":"https:\/\/huguesg.fr\/site\/index.php\/les-finances-de-sncf-reseau\/","title":{"rendered":"Les finances de SNCF R\u00e9seau"},"content":{"rendered":"\n<p>Acteur central du syst\u00e8me ferroviaire fran\u00e7ais, SNCF R\u00e9seau porte une responsabilit\u00e9 strat\u00e9gique : financer, entretenir et moderniser un r\u00e9seau qui conditionne \u00e0 la fois la mobilit\u00e9 des voyageurs, la comp\u00e9titivit\u00e9 du fret et la transition \u00e9cologique du pays. Derri\u00e8re cette mission se cache une \u00e9quation \u00e9conomique complexe, o\u00f9 se croisent recettes r\u00e9gul\u00e9es, contraintes de performance financi\u00e8re et besoins d\u2019investissement massifs sur le long terme. Pour en comprendre les ressorts, cet article propose d\u2019explorer successivement les principales sources de revenus de SNCF R\u00e9seau, les indicateurs cl\u00e9s qui structurent sa trajectoire financi\u00e8re, puis l\u2019ampleur et les enjeux de ses investissements, au c\u0153ur des transformations du ferroviaire fran\u00e7ais.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Les recettes de SNCF R\u00e9seau<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1.1) Les p\u00e9ages<\/h3>\n\n\n\n<p>La principale source de revenus de SNCF R\u00e9seau repose sur les p\u00e9ages acquitt\u00e9s par les entreprises ferroviaires pour l\u2019utilisation du r\u00e9seau. Si SNCF Voyageurs en constitue historiquement le principal contributeur, l\u2019ouverture \u00e0 la concurrence a progressivement \u00e9largi le p\u00e9rim\u00e8tre \u00e0 d\u2019autres acteurs, notamment dans le fret et les services voyageurs conventionn\u00e9s. Ces p\u00e9ages se structurent autour de plusieurs composantes : d\u2019une part, la redevance d\u2019acc\u00e8s, majoritairement financ\u00e9e par les autorit\u00e9s organisatrices (\u00c9tat et r\u00e9gions) pour garantir l\u2019\u00e9quilibre des services publics ; d\u2019autre part, les redevances directement acquitt\u00e9es par les entreprises ferroviaires, incluant la redevance de march\u00e9, la redevance de circulation ainsi que les redevances li\u00e9es \u00e0 l\u2019\u00e9nergie de traction ; enfin, des recettes plus marginales compl\u00e8tent cet ensemble. L\u2019\u00e9volution de ces diff\u00e9rentes cat\u00e9gories au fil du temps permet de mieux comprendre les dynamiques \u00e9conomiques du syst\u00e8me ferroviaire fran\u00e7ais, comme l\u2019illustre le graphique ci-dessous.<\/p>\n\n\n\n<!doctype html>\n<html lang=\"fr\">\n<head>\n  <meta charset=\"utf-8\" \/>\n  <title>3 barres par ann\u00e9e + courbe (Google Charts)<\/title>\n  <script src=\"https:\/\/www.gstatic.com\/charts\/loader.js\"><\/script>\n  <style>\n    body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; margin: 24px; }\n    #comboChartContainer { width: 100%; height: 560px; }\n  <\/style>\n<\/head>\n<body>\n  <div id=\"comboChartContainer\"><\/div>\n\n  <script>\n    \/\/ =========================\n    \/\/ 1) Param\u00e8tres\n    \/\/ =========================\n    const CSV_URL = 'https:\/\/huguesg.fr\/docs\/peages.csv';\n\n    \/\/ Expressions pour retrouver les colonnes par nom (tol\u00e8re casse\/accents\/variantes)\n    const COLUMN_PATTERNS = {\n      periodLabel:       [\/Ann[\u00e9e]e\/i],                        \/\/ \"P\u00e9rim\u00e8tre\"\n      peagesVoyageurs:   [\/Peages SNCF Voyageurs\/i],             \/\/ \"P\u00e9ages pay\u00e9s par SNCF Voyageurs\"\n      ra:                [\/^RA$\/i],\n      rm:                [\/^RM$\/i],\n      rc:                [\/^RC$\/i],\n      rce_rcte:          [\/rce?\\s*&\\s*rcte\/i, \/rce.*rcte\/i],     \/\/ \"RCE & RCTE\"\n      autres:            [\/autres.*redev\/i],                    \/\/ \"Autres redevances\"\n      compensationFret:  [\/compensation.*fret\/i]                \/\/ \"Compensation Fret\"\n    };\n\n    \/\/ =========================\n    \/\/ 2) Cycle de vie\n    \/\/ =========================\n    google.charts.load('current', { packages: ['corechart'] });\n    google.charts.setOnLoadCallback(loadAndDraw);\n\n    async function loadAndDraw() {\n      try {\n        const csvText = await fetchCsvText(CSV_URL);\n        const { parsedRows } = parseCsvAutoSeparator(csvText);\n        const structured = buildStructuredRows(parsedRows);\n        drawComboChart(structured);\n      } catch (err) {\n        console.error(err);\n        document.getElementById('comboChartContainer').innerHTML =\n          '<p>Erreur : ' + (err.message || err) + '<\/p>';\n      }\n    }\n\n    \/\/ =========================\n    \/\/ 3) Chargement & parsing CSV\n    \/\/ =========================\n    async function fetchCsvText(url) {\n      const response = await fetch(url, { cache: 'no-store' });\n      if (!response.ok) throw new Error('\u00c9chec du chargement du CSV (' + response.status + ')');\n      return response.text();\n    }\n\n    function parseCsvAutoSeparator(csvText) {\n      const normalized = csvText.replace(\/\\r\\n?\/g, '\\n').trim();\n      const lines = normalized.split('\\n').filter(Boolean);\n      const seps = [';', '\\t', ','];\n      const choose = seps\n        .map(sep => ({ sep, score: lines.slice(0, 5).reduce((a, l) => a + l.split(sep).length, 0) }))\n        .sort((a, b) => b.score - a.score)[0].sep;\n      const parsedRows = lines.map(l => l.split(choose).map(c => c.trim()));\n      return { parsedRows, sep: choose };\n    }\n\n    \/\/ =========================\n    \/\/ 4) Mise en forme des donn\u00e9es\n    \/\/ =========================\n    function buildStructuredRows(parsedRows) {\n      const [headerRow, ...bodyRows] = parsedRows;\n\n      \/\/ a) R\u00e9sout index de chaque colonne via les patterns\n      const colIndex = {};\n      for (const [key, regexes] of Object.entries(COLUMN_PATTERNS)) {\n        colIndex[key] = headerRow.findIndex(h => regexes.some(re => re.test((h || '').toString())));\n      }\nconsole.log(colIndex);\n      \/\/ b) Construit les lignes dans l'ordre voulu :\n      \/\/    [P\u00e9riode, P\u00e9ages, RA, Somme(RM+RC+RCE+RCTE+Autres), Compensation]\n      const chartRows = [];\n      for (const row of bodyRows) {\n        const periodLabel = getCell(row, colIndex.periodLabel);\n        if (!periodLabel) continue;\n\n        const peagesVoyageurs  = toNumberFR(getCell(row, colIndex.peagesVoyageurs));\n        const ra               = toNumberFR(getCell(row, colIndex.ra));\n        const rm               = toNumberFR(getCell(row, colIndex.rm));\n        const rc               = toNumberFR(getCell(row, colIndex.rc));\n        const rce_rcte         = toNumberFR(getCell(row, colIndex.rce_rcte));\n        const autres           = toNumberFR(getCell(row, colIndex.autres));\n        const compensationFret = toNumberFR(getCell(row, colIndex.compensationFret));\n\n        const sommeBlocRMRCRCEAutres = (rm || 0) + (rc || 0) + (rce_rcte || 0) + (autres || 0);\n\n        chartRows.push([\n          String(periodLabel),\n          peagesVoyageurs ?? null,\n          ra ?? null,\n          sommeBlocRMRCRCEAutres,           \/\/ <-- une seule barre pour la somme\n          compensationFret ?? null\n        ]);\n      }\n\n      return {\n        headers: [\n          'P\u00e9rim\u00e8tre',\n          'P\u00e9ages pay\u00e9s par SNCF Voyageurs',\n          'RA',\n          'RM+RC+RCE+RCTE+Autres',\n          'Compensation Fret'\n        ],\n        rows: chartRows\n      };\n    }\n\n    function getCell(row, idx) {\n      return (idx == null || idx < 0 || idx >= row.length) ? null : (row[idx] === '' ? null : row[idx]);\n    }\n\n    function toNumberFR(v) {\n      if (v == null) return null;\n      const n = Number(String(v).replace(\/\\s+\/g, '').replace(',', '.'));\n      return Number.isFinite(n) ? n : null;\n    }\n\n    \/\/ =========================\n    \/\/ 5) Trac\u00e9 ComboChart (3 barres + 1 ligne)\n    \/\/ =========================\n    function drawComboChart(structured) {\n      \/\/ A. DataTable\n      const dataTable = new google.visualization.DataTable();\n      dataTable.addColumn('string', structured.headers[0]); \/\/ P\u00e9rim\u00e8tre\n      dataTable.addColumn('number', structured.headers[1]); \/\/ P\u00e9ages (ligne)\n      dataTable.addColumn('number', structured.headers[2]); \/\/ RA (barre)\n      dataTable.addColumn('number', structured.headers[3]); \/\/ Somme RM+RC+RCE+RCTE+Autres (barre)\n      dataTable.addColumn('number', structured.headers[4]); \/\/ Compensation Fret (barre)\n      dataTable.addRows(structured.rows);\n\n      \/\/ B. Calcul de l'\u00e9chelle (max commun)\n      let maxY = 0;\n      for (let r = 0; r < dataTable.getNumberOfRows(); r++) {\n        maxY = Math.max(\n          maxY,\n          dataTable.getValue(r, 1) || 0, \/\/ p\u00e9ages\n          dataTable.getValue(r, 2) || 0, \/\/ RA\n          dataTable.getValue(r, 3) || 0, \/\/ Somme bloc\n          dataTable.getValue(r, 4) || 0  \/\/ compensation\n        );\n      }\n      maxY = Math.ceil(maxY * 1.1);\n\n      \/\/ C. Options : 3 barres group\u00e9es + 1 courbe\n      const comboOptions = {\n        title: 'RA \/ (RM+RC+RCE+RCTE+Autres) \/ Compensation Fret + P\u00e9ages',\n        height: 560,\n        legend: { position: 'top' },\n        seriesType: 'bars',\n        isStacked: false, \/\/ \u2190 pas d\u2019empilage : 3 barres bien distinctes\n        series: {\n          0: { type: 'line', lineWidth: 3, pointSize: 5 }, \/\/ P\u00e9ages\n          1: { type: 'bars' },                              \/\/ RA\n          2: { type: 'bars' },                              \/\/ Somme bloc\n          3: { type: 'bars' }                               \/\/ Compensation\n        },\n        vAxis: { title: 'M\u20ac', viewWindow: { min: 0, max: maxY } },\n        hAxis: { title: 'P\u00e9rim\u00e8tre (ann\u00e9e)' },\n        bar: { groupWidth: '70%' },\n        colors: ['#1f2937', '#2563eb', '#60a5fa', '#f59e0b'] \/\/ ligne + 3 barres\n      };\n\n      \/\/ D. Rendu\n      const chart = new google.visualization.ComboChart(document.getElementById('comboChartContainer'));\n      chart.draw(dataTable, comboOptions);\n    }\n  <\/script>\n<\/body>\n<\/html>\n\n\n\n<h3 class=\"wp-block-heading\">1.2) Le fonds de concours<\/h3>\n\n\n\n<p>La deuxi\u00e8me grande source de financement de SNCF R\u00e9seau repose sur le fonds de concours, qui est un m\u00e9canisme budg\u00e9taire permettant aux dividendes issus des r\u00e9sultats du groupe SNCF d'\u00eatre fl\u00e9ch\u00e9s par l'Etat vers SNCF R\u00e9seau. Il est destin\u00e9 \u00e0 soutenir l\u2019entretien, la r\u00e9g\u00e9n\u00e9ration et le d\u00e9veloppement du r\u00e9seau. Ces financements jouent un r\u00f4le d\u00e9terminant pour compenser l\u2019insuffisance des seules recettes de p\u00e9ages face \u00e0 l\u2019ampleur des besoins. Leur trajectoire a \u00e9t\u00e9 marqu\u00e9e ces derni\u00e8res ann\u00e9es par une hausse significative, notamment dans le cadre du plan de relance fran\u00e7ais 2020, qui a acc\u00e9l\u00e9r\u00e9 les investissements ferroviaires pour r\u00e9pondre \u00e0 des objectifs \u00e0 la fois \u00e9conomiques et environnementaux. <\/p>\n\n\n\n<script src=\"https:\/\/www.gstatic.com\/charts\/loader.js\"><\/script>\n  <style>\n    body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; margin: 24px; }\n    .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); gap: 18px; }\n    .chart { width: 100%; height: 360px; }\n  <\/style>\n    <div id=\"chartFondsPlan\" class=\"chart\" aria-label=\"Fonds de concours et Plan de relance\"><\/div>\n\n\n  <script>\n    \/\/ =========================\n    \/\/ 1) Param\u00e8tres & mapping colonnes\n    \/\/ =========================\n    const CSV_URL2 = 'https:\/\/huguesg.fr\/docs\/cfl-reseau.csv';\n\n    \/\/ Tol\u00e8re casses\/accents\/variantes d\u2019intitul\u00e9s\n    const COL2 = {\n      year:              [\/^ann[\u00e9e]e\/i],\n      cfl:               [\/^cfl.*sncf.*r[\u00e9e]seau\/i],\n      detteNette:        [\/^dette\\s*nette\/i],\n      ratioRegleOr:      [\/^ratio.*r[\u00e8e]gle.*or\/i],\n      fondsConcours:     [\/^fonds.*concours\/i],\n      planRelance:       [\/^plan.*relance\/i]\n    };\n\n    \/\/ =========================\n    \/\/ 2) Cycle de vie\n    \/\/ =========================\n    google.charts.load('current', { packages: ['corechart'] });\n    google.charts.setOnLoadCallback(initFromCsv);\n\n    async function initFromCsv() {\n      try {\n        const csv = await fetchCsv(CSV_URL2);\n        const { rows } = parseCsvSmart(csv);\n        const { headers, data } = structureData(rows);\n        drawAllCharts(headers, data);\n      } catch (e) {\n        console.error(e);\n        document.querySelectorAll('.chart').forEach(el => el.innerHTML = '<p>Chargement impossible : ' + (e.message || e) + '<\/p>');\n      }\n    }\n\n    \/\/ =========================\n    \/\/ 3) Chargement & parsing CSV\n    \/\/ =========================\n    async function fetchCsv(url) {\n      const r = await fetch(url, { cache: 'no-store' });\n      if (!r.ok) throw new Error('\u00c9chec du chargement du CSV (' + r.status + ')');\n      return r.text();\n    }\n\n    \/\/ D\u00e9tection du s\u00e9parateur ; , ou tabulation + trim\n    function parseCsvSmart(text) {\n      const lines = text.replace(\/\\r\\n?\/g, '\\n').trim().split('\\n').filter(Boolean);\n      const seps = [';', '\\t', ','];\n      const best = seps\n        .map(sep => ({ sep, score: lines.slice(0, 5).reduce((a, l) => a + l.split(sep).length, 0) }))\n        .sort((a, b) => b.score - a.score)[0].sep;\n      const rows = lines.map(l => l.split(best).map(c => c.trim()));\n      return { rows, sep: best };\n    }\n\n    \/\/ =========================\n    \/\/ 4) Normalisation des donn\u00e9es\n    \/\/ =========================\n    function structureData(rows) {\n      const [headerRow, ...body] = rows;\n      const idx = resolveColumnIndexes(headerRow);\n\n      const data = body\n        .map(r => ({\n          year:              getCell(r, idx.year),\n          cfl:               toNumberFR(getCell(r, idx.cfl)),\n          detteNette:        toNumberFR(getCell(r, idx.detteNette)),\n          ratioRegleOr:      toNumberFR(getCell(r, idx.ratioRegleOr)),\n          fondsConcours:     toNumberFR(getCell(r, idx.fondsConcours)),\n          planRelance:       toNumberFR(getCell(r, idx.planRelance))\n        }))\n        \/\/ ignore lignes sans ann\u00e9e\n        .filter(row => row.year);\n\n      return { headers: { ...idx }, data };\n    }\n\n    function resolveColumnIndexes(headers) {\n      const find = (regexes) => headers.findIndex(h => regexes.some(re => re.test((h || '').toString())));\n      return {\n        year:          find(COL2.year),\n        cfl:           find(COL2.cfl),\n        detteNette:    find(COL2.detteNette),\n        ratioRegleOr:  find(COL2.ratioRegleOr),\n        fondsConcours: find(COL2.fondsConcours),\n        planRelance:   find(COL2.planRelance)\n      };\n    }\n\n    function getCell(row, i) {\n      return (i == null || i < 0 || i >= row.length) ? null : (row[i] === '' ? null : row[i]);\n    }\n\n    function toNumberFR(v) {\n      if (v == null) return null;\n      const n = Number(String(v).replace(\/\\s+\/g, '').replace(',', '.'));\n      return Number.isFinite(n) ? n : null;\n    }\n\n    \/\/ =========================\n    \/\/ 5) Construction des DataTables & trac\u00e9s\n    \/\/ =========================\n    function drawAllCharts(headers, data) {\n      \/\/drawBarCFL(data);\n      \/\/drawBarDette(data);\n      \/\/drawLineRatio(data);\n      drawGroupedFondsPlan(data);\n    }\n\n    \/\/ --- CFL : barres ---\n    function drawBarCFL(data) {\n      const dt = new google.visualization.DataTable();\n      dt.addColumn('string', 'Ann\u00e9e');\n      dt.addColumn('number', 'CFL SA SNCF R\u00e9seau');\n      dt.addRows(data.map(d => [String(d.year), d.cfl]));\n\n      const options = {\n        title: 'CFL SA SNCF R\u00e9seau',\n        height: 360,\n        legend: 'none',\n        vAxis: { title: 'M\u20ac' },\n        hAxis: { title: 'Ann\u00e9e' },\n        colors: ['#2563eb'],\n        bar: { groupWidth: '60%' }\n      };\n\n      new google.visualization.ColumnChart(document.getElementById('chartCFL')).draw(dt, options);\n    }\n\n    \/\/ --- Dette nette : barres ---\n    function drawBarDette(data) {\n      const dt = new google.visualization.DataTable();\n      dt.addColumn('string', 'Ann\u00e9e');\n      dt.addColumn('number', 'Dette nette');\n      dt.addRows(data.map(d => [String(d.year), d.detteNette]));\n\n      const options = {\n        title: 'Dette nette',\n        height: 360,\n        legend: 'none',\n        vAxis: { title: 'M\u20ac' },\n        hAxis: { title: 'Ann\u00e9e' },\n        colors: ['#1f2937'],\n        bar: { groupWidth: '60%' }\n      };\n\n      new google.visualization.ColumnChart(document.getElementById('chartDette')).draw(dt, options);\n    }\n\n    \/\/ --- Ratio r\u00e8gle d\u2019or : ligne ---\n    function drawLineRatio(data) {\n      const dt = new google.visualization.DataTable();\n      dt.addColumn('string', 'Ann\u00e9e');\n      dt.addColumn('number', \"Ratio r\u00e8gle d'or\");\n      dt.addRows(data.map(d => [String(d.year), d.ratioRegleOr]));\n\n      const options = {\n        title: \"Ratio r\u00e8gle d'or\",\n        height: 360,\n        legend: 'none',\n        vAxis: { title: '%', viewWindowMode: 'pretty' },\n        hAxis: { title: 'Ann\u00e9e' },\n        lineWidth: 3,\n        pointSize: 5,\n        colors: ['#10b981']\n      };\n\n      new google.visualization.LineChart(document.getElementById('chartRatio')).draw(dt, options);\n    }\n\n    \/\/ --- Fonds de concours + Plan de relance : 2 barres group\u00e9es ---\n    function drawGroupedFondsPlan(data) {\n      const dt = new google.visualization.DataTable();\n      dt.addColumn('string', 'Ann\u00e9e');\n      dt.addColumn('number', 'Fonds de concours');\n      dt.addColumn('number', 'Plan de relance');\n      dt.addRows(data.map(d => [String(d.year), d.fondsConcours, d.planRelance]));\n\n      const options = {\n        title: 'Fonds de concours et Plan de relance',\n        height: 360,\n        legend: { position: 'top' },\n        vAxis: { title: 'M\u20ac' },\n        hAxis: { title: 'Ann\u00e9e' },\n        isStacked: true, \/\/ \u2190 barres group\u00e9es (c\u00f4te \u00e0 c\u00f4te)\n        colors: ['#60a5fa', '#f59e0b'],\n        bar: { groupWidth: '60%' }\n      };\n\n      new google.visualization.ColumnChart(document.getElementById('chartFondsPlan')).draw(dt, options);\n    }\n  <\/script>\n\n\n\n<h2 class=\"wp-block-heading\">2. Indicateurs financiers<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">2.1) Dette nette<\/h3>\n\n\n\n<p>L\u2019analyse de la trajectoire financi\u00e8re de SNCF R\u00e9seau ne peut se faire sans examiner l\u2019\u00e9volution de sa dette, longtemps au c\u0153ur de son mod\u00e8le \u00e9conomique. Celle-ci a connu une inflexion majeure avec les reprises successives op\u00e9r\u00e9es par l\u2019\u00c9tat, \u00e0 hauteur de 25 milliards d\u2019euros en 2020 puis 10 milliards en 2022, modifiant profond\u00e9ment le profil d\u2019endettement de l\u2019entreprise. Au-del\u00e0 de leur impact comptable, ces op\u00e9rations traduisent une r\u00e9alit\u00e9 structurelle : une part significative de la dette de SNCF R\u00e9seau r\u00e9sulte de choix d\u2019investissement historiquement port\u00e9s par la puissance publique, notamment lors des grandes phases de d\u00e9veloppement du r\u00e9seau ferroviaire. Ainsi, la dette ne refl\u00e8te pas uniquement une dynamique d\u2019exploitation, mais aussi des orientations strat\u00e9giques nationales sur le long terme. Le graphique ci-dessous permet d\u2019en visualiser l\u2019\u00e9volution, en mettant en \u00e9vidence les effets de ces reprises et les tendances sous-jacentes.<\/p>\n\n\n\n<div id=\"wp_chart_dette\" style=\"height:360px\"><\/div>\n<script src=\"https:\/\/www.gstatic.com\/charts\/loader.js\"><\/script>\n<script>\n(function DebtBarChartWP(){\n  const CSV_URL = 'https:\/\/huguesg.fr\/docs\/cfl-reseau.csv';\n  const DEBT_COL_PATTERNS = {\n    year: [\/^ann[\u00e9e]e\/i],\n    debt: [\/^dette\\s*nette\/i]\n  };\n\n  google.charts.load('current', {packages:['corechart']});\n  google.charts.setOnLoadCallback(initDebt);\n\n  async function initDebt(){\n    try{\n      const csv = await fetch(CSV_URL, {cache:'no-store'}); if(!csv.ok) throw new Error('HTTP '+csv.status);\n      const text = await csv.text();\n      const rows = parseCsvSmartDebt(text);\n      const [headers,...body] = rows;\n      const yearIdx = headers.findIndex(h=>DEBT_COL_PATTERNS.year.some(re=>re.test(h||'')));\n      const debtIdx = headers.findIndex(h=>DEBT_COL_PATTERNS.debt.some(re=>re.test(h||'')));\n\n      const dt = new google.visualization.DataTable();\n      dt.addColumn('string','Ann\u00e9e');\n      dt.addColumn('number','Dette nette');\n      dt.addRows(body.filter(r=>r[yearIdx]).map(r=>[String(r[yearIdx]), toNumberFrDebt(r[debtIdx])]));\n\n      const opts = {\n        title: 'Dette nette',\n        height: 360,\n        legend: 'none',\n        vAxis: { title: 'M\u20ac' },\n        hAxis: { title: 'Ann\u00e9e' },\n        bar: { groupWidth: '60%' },\n        colors: ['#1f2937']\n      };\n      new google.visualization.ColumnChart(document.getElementById('wp_chart_dette')).draw(dt, opts);\n    }catch(e){\n      document.getElementById('wp_chart_dette').innerHTML = 'Erreur chargement CSV : ' + (e.message||e);\n    }\n  }\n\n  function parseCsvSmartDebt(text){\n    const lines = text.replace(\/\\r\\n?\/g,'\\n').trim().split('\\n').filter(Boolean);\n    const seps=[';','\\t',',']; const sep = seps.map(s=>({s,score:lines.slice(0,5).reduce((a,l)=>a+l.split(s).length,0)})).sort((a,b)=>b.score-a.score)[0].s;\n    return lines.map(l=>l.split(sep).map(c=>c.trim()));\n  }\n  function toNumberFrDebt(v){ if(v==null||v==='') return null; const n=Number(String(v).replace(\/\\s+\/g,'').replace(',', '.')); return Number.isFinite(n)?n:null; }\n})();\n<\/script>\n\n\n\n<h3 class=\"wp-block-heading\">2.2) Cash-Flow libre<\/h3>\n\n\n\n<p>L\u2019\u00e9volution du cash-flow libre constitue un indicateur cl\u00e9 pour appr\u00e9cier la soutenabilit\u00e9 financi\u00e8re de SNCF R\u00e9seau, en traduisant sa capacit\u00e9 \u00e0 couvrir ses investissements par ses ressources propres. Longtemps structurellement n\u00e9gatif, ce cash-flow libre s\u2019inscrit d\u00e9sormais dans une trajectoire de redressement progressive vers l\u2019\u00e9quilibre. Cette am\u00e9lioration repose sur plusieurs facteurs, au premier rang desquels la reprise partielle de la dette par l\u2019\u00c9tat, qui a permis de r\u00e9duire significativement les charges financi\u00e8res et d\u2019all\u00e9ger le poids des int\u00e9r\u00eats. \u00c0 cela s\u2019ajoutent des efforts de ma\u00eetrise des co\u00fbts et une \u00e9volution plus favorable des recettes. Le graphique ci-dessous illustre cette dynamique, en mettant en \u00e9vidence le chemin parcouru.<\/p>\n\n\n\n<div id=\"wp_chart_cfl\" style=\"height:360px\"><\/div>\n<script src=\"https:\/\/www.gstatic.com\/charts\/loader.js\"><\/script>\n<script>\n(function CflBarChartWP(){\n  const CSV_URL = 'https:\/\/huguesg.fr\/docs\/cfl-reseau.csv';\n\n  \/\/ Colonnes attendues (tol\u00e8re casses\/accents\/variantes)\n  const CFL_COL_PATTERNS = {\n    year: [\/^ann[\u00e9e]e\/i],\n    cfl: [\/^cfl.*sncf.*r[\u00e9e]seau\/i]\n  };\n\n  google.charts.load('current', {packages:['corechart']});\n  google.charts.setOnLoadCallback(initCFL);\n\n  async function initCFL(){\n    try{\n      const csvText = await fetchCsvCFL(CSV_URL);\n      const rows = parseCsvSmartCFL(csvText);\n      const {yearIdx, cflIdx, dataRows} = pickColumnsCFL(rows);\n      const dt = new google.visualization.DataTable();\n      dt.addColumn('string', 'Ann\u00e9e');\n      dt.addColumn('number', 'CFL SA SNCF R\u00e9seau');\n      dt.addRows(\n        dataRows.map(r => [String(r[yearIdx]), toNumberFrCFL(r[cflIdx])])\n      );\n\n      const opts = {\n        title: 'CFL SA SNCF R\u00e9seau',\n        height: 360,\n        legend: 'none',\n        vAxis: { title: 'M\u20ac' },\n        hAxis: { title: 'Ann\u00e9e' },\n        bar: { groupWidth: '60%' },\n        colors: ['#2563eb']\n      };\n      new google.visualization.ColumnChart(document.getElementById('wp_chart_cfl')).draw(dt, opts);\n    }catch(e){\n      document.getElementById('wp_chart_cfl').innerHTML = 'Erreur chargement CSV : ' + (e.message||e);\n    }\n  }\n\n  async function fetchCsvCFL(url){ const r = await fetch(url, {cache:'no-store'}); if(!r.ok) throw new Error('HTTP ' + r.status); return r.text(); }\n  function parseCsvSmartCFL(text){\n    const lines = text.replace(\/\\r\\n?\/g,'\\n').trim().split('\\n').filter(Boolean);\n    const seps = [';', '\\t', ','];\n    const sep = seps.map(s=>({s,score:lines.slice(0,5).reduce((a,l)=>a+l.split(s).length,0)}))\n                    .sort((a,b)=>b.score-a.score)[0].s;\n    return lines.map(l => l.split(sep).map(c => c.trim()));\n  }\n  function pickColumnsCFL(rows){\n    const [headers,...body]=rows;\n    const yearIdx = headers.findIndex(h=>CFL_COL_PATTERNS.year.some(re=>re.test(h||'')));\n    const cflIdx  = headers.findIndex(h=>CFL_COL_PATTERNS.cfl.some(re=>re.test(h||'')));\n    return {yearIdx, cflIdx, dataRows: body.filter(r=>r[yearIdx])};\n  }\n  function toNumberFrCFL(v){ if(v==null||v==='') return null; const n=Number(String(v).replace(\/\\s+\/g,'').replace(',', '.')); return Number.isFinite(n)?n:null; }\n})();\n<\/script>\n\n\n\n<h2 class=\"wp-block-heading\">3. Investissements<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">3.1) Investissements sur le r\u00e9seau structurant<\/h3>\n\n\n\n<p>L\u2019analyse des investissements r\u00e9alis\u00e9s par SNCF R\u00e9seau sur le r\u00e9seau structurant met en lumi\u00e8re une dynamique de mont\u00e9e en puissance engag\u00e9e depuis 2020. Port\u00e9e par une volont\u00e9 de rattrapage sur la r\u00e9g\u00e9n\u00e9ration des infrastructures existantes et de modernisation des grands axes, cette trajectoire traduit un effort soutenu pour am\u00e9liorer la performance, la robustesse et la capacit\u00e9 du r\u00e9seau. Le graphique ci-dessous illustre cette progression des investissements.<\/p>\n\n\n\n<script src=\"https:\/\/www.gstatic.com\/charts\/loader.js\"><\/script>\n<style>\n  #chart-renouv { height: 520px; max-width: 1100px; margin: 24px auto; }\n<\/style>\n<div id=\"chart-renouv\"><\/div>\n\n<script>\n  \/\/ ========= CONFIG =========\n  const DATA_URL_renouv = 'https:\/\/huguesg.fr\/docs\/cfl-reseau.csv'; \/\/ <-- remplacez par l\u2019URL r\u00e9el\n\n  \/\/ ========= UTILS =========\n  const parseNumberFR_renouv = (s) =>\n    parseFloat(String(s ?? '').replace(\/\\u00A0\/g,' ').trim().replace(\/\\s\/g,'').replace(',', '.'));\n\n  const normalize_renouv = (s) =>\n    String(s || '')\n      .normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '') \/\/ enl\u00e8ve accents\n      .replace(\/\\s+\/g, ' ').trim().toLowerCase();\n\n  function detectSep_renouv(line) {\n    let best = ';', bestCount = 1;\n    for (const sep of ['\\t','; ',',']) {\n      const n = line.split(sep).length;\n      if (n > bestCount) { best = sep; bestCount = n; }\n    }\n    return best;\n  }\n\n  async function fetchCSV_renouv(url) {\n    const resp = await fetch(url, { cache: 'no-cache', mode: 'cors' });\n    if (!resp.ok) throw new Error('HTTP ' + resp.status);\n    const buf = await resp.arrayBuffer();\n    \/\/ UTF-8 d\u2019abord, fallback Windows-1252 si besoin (accents)\n    let text = new TextDecoder('utf-8', { fatal: false }).decode(buf);\n    if (text.includes('\\uFFFD')) {\n      try { text = new TextDecoder('windows-1252').decode(buf); } catch {}\n    }\n    return text.replace(\/^\\uFEFF\/, '');\n  }\n\n  function parseCSV_renouv(text) {\n    const lines = text.split(\/\\r?\\n\/).filter(l => l.trim().length > 0);\n    if (!lines.length) return { headers: [], rows: [] };\n    const sep = detectSep_renouv(lines[0]);\n    const split = l => l.split(sep).map(x => x.trim());\n\n    const headers = split(lines[0]);\n    const rows = lines.slice(1).map(split);\n    return { headers, rows };\n  }\n\n  \/\/ extrait la s\u00e9rie \"Investissements renouvellement et performance\"\n  function extractSeries_renouv(headers, rows) {\n    \/\/ trouver colonne ann\u00e9e\n    let idxYear = headers.findIndex(h => \/^annee$\/.test(normalize_renouv(h)));\n    if (idxYear === -1) idxYear = 0; \/\/ fallback : premi\u00e8re colonne\n\n    \/\/ trouver la colonne cible (tol\u00e9rant aux variations d\u2019accents\/casse\/espaces)\n    const targetName = 'investissements renouvellement et performance';\n    const idxRenouv = headers.findIndex(h => normalize_renouv(h) === targetName);\n    if (idxRenouv === -1) return new Map();\n\n    const byYear = new Map();\n    rows.forEach(r => {\n      const y = parseInt(String(r[idxYear]).replace(\/\\D\/g,''), 10);\n      if (!Number.isFinite(y)) return;\n      const v = parseNumberFR_renouv(r[idxRenouv]);\n      if (Number.isFinite(v)) byYear.set(y, v);\n    });\n\n    return byYear;\n  }\n\n  function buildDataTable_renouv(byYear) {\n    const data = new google.visualization.DataTable();\n    data.addColumn('string', 'Ann\u00e9e');\n    data.addColumn('number', 'Financement r\u00e9alis\u00e9');\n    data.addColumn({ type: 'string', role: 'annotation' });\n\n    const years = Array.from(byYear.keys()).sort((a,b)=>a-b);\n    years.forEach(y => {\n      const val = byYear.get(y);\n      data.addRow([String(y), val, String(val)]);\n    });\n\n    \/\/ format FR sans d\u00e9cimales\n    const nf = new google.visualization.NumberFormat({ groupingSymbol: ' ', decimalSymbol: ',', fractionDigits: 0 });\n    nf.format(data, 1);\n    return data;\n  }\n\n  function drawLine_renouv(data) {\n    const options = {\n      legend: { position: 'top' },\n      chartArea: { left: 70, right: 30, top: 40, height: '70%' },\n      vAxis: { title: 'Montant (M\u20ac)', viewWindow: { min: 0 } },\n      hAxis: { title: 'Ann\u00e9e' },\n      lineWidth: 3,\n      pointSize: 6,\n      annotations: { alwaysOutside: true },\n      series: {\n        0: { color: '#1f77b4' }, \/\/ bleu plus fonc\u00e9 (jusqu\u2019\u00e0 2024)\n      }\n    };\n    const chart = new google.visualization.LineChart(document.getElementById('chart-renouv'));\n    chart.draw(data, options);\n    window.addEventListener('resize', () => chart.draw(data, options));\n  }\n\n  \/\/ ========= MAIN =========\n  google.charts.load('current', { packages: ['corechart'] });\n  google.charts.setOnLoadCallback(async () => {\n    try {\n      const csv = await fetchCSV_renouv(DATA_URL_renouv);\n      const parsed = parseCSV_renouv(csv);\n      const byYear = extractSeries_renouv(parsed.headers, parsed.rows);\n      const data = buildDataTable_renouv(byYear);\n      drawLine_renouv(data);\n    } catch (err) {\n      document.getElementById('chart-renouv').innerHTML =\n        '<p style=\"color:#b00\">Erreur de chargement\/parsing. V\u00e9rifiez l\u2019URL du CSV, le nom de colonne et CORS.<\/p>';\n      console.error(err);\n    }\n  });\n<\/script>\n\n\n\n<h3 class=\"wp-block-heading\">3.2) Grands projets<\/h3>\n\n\n\n<p>En compl\u00e9ment des investissements consacr\u00e9s au r\u00e9seau existant, SNCF R\u00e9seau porte \u00e9galement des investissements significatifs sur de grands projets, qu\u2019ils soient d\u2019initiative nationale ou r\u00e9gionale (lignes nouvelles, grands am\u00e9nagements, n\u0153uds ferroviaires). L\u2019enjeu central r\u00e9side dans l\u2019articulation de ces projets avec les besoins de r\u00e9g\u00e9n\u00e9ration et de modernisation du r\u00e9seau structurant afin d'\u00e9viter qu'ils ne soient en concurrence. Le graphique ci-dessous permet ainsi d\u2019analyser l\u2019\u00e9volution de ces investissements d\u00e9di\u00e9s aux grands projets, tout en mettant en perspective leur poids relatif dans l\u2019effort global d\u2019investissement de SNCF R\u00e9seau.<\/p>\n\n\n\n<script src=\"https:\/\/www.gstatic.com\/charts\/loader.js\"><\/script>\n  <style>\n    #chartAftInvestReseauDev { height: 560px; max-width: 1100px; margin: 0 auto; }\n  <\/style>\n  <div id=\"chartAftInvestReseauDev\"><\/div>\n  <script>\n    \/\/ ========= CONFIG =========\n    const DATA_URL_AftInvestReseauDev = 'https:\/\/huguesg.fr\/docs\/cfl-reseau.csv';\n\n    \/\/ ========= UTILITAIRES =========\n    const parseNumberFR_AftInvestReseauDev = (s) =>\n      parseFloat(String(s ?? '').trim().replace(\/\\s\/g, '').replace(',', '.'));\n\n    const splitSmart_AftInvestReseauDev = (line) => {\n      for (const sep of ['\\t', ';', ',']) {\n        const parts = line.split(sep);\n        if (parts.length > 1) return parts;\n      }\n      return [line];\n    };\n\n    const norm_AftInvestReseauDev = (s) => String(s || '')\n      .normalize('NFD').replace(\/[\\u0300-\\u036f]\/g, '')\n      .toLowerCase().replace(\/\\s+\/g, ' ').trim();\n\n    async function fetchCSV_AftInvestReseauDev(url) {\n      const resp = await fetch(url, { cache: 'no-cache' });\n      if (!resp.ok) throw new Error('HTTP ' + resp.status);\n      return await resp.text();\n    }\n\n    function parseCSV_AftInvestReseauDev(text) {\n      const rows = text.split(\/\\r?\\n\/).map(l => l.trim()).filter(Boolean).map(splitSmart_AftInvestReseauDev);\n      if (!rows.length) return { headers: [], rows: [] };\n      const headers = rows[0].map(h => h.trim());\n      const dataRows = rows.slice(1);\n      return { headers, rows: dataRows };\n    }\n\n    function buildDataTable_AftInvestReseauDev(headers, rows) {\n      const idxByName = {};\n\n      headers.forEach((h, i) => idxByName[norm_AftInvestReseauDev(h)] = i);\n      const key = (s) => idxByName[norm_AftInvestReseauDev(s)];\n\n      const idxYear = key('Annee');\n      const idxGP = key('Investissements Grands Projets de developpement');\n      const idxPR = key('Investissements Projets regionaux de developpement');\n      const idxConformite = key('Investissements Mise en conformite du reseau');\n      const idxRenouvPerf = key('Investissements renouvellement et performance');\n      const idxFoncAutres = key('Investissements Fonciers et autres');\n      const idxIndus = key('Investissements industriels');\n\n      if ([idxYear, idxGP, idxPR, idxConformite, idxRenouvPerf, idxFoncAutres, idxIndus]\n          .some(i => typeof i !== 'number')) {\n        throw new Error(\"Impossible de rep\u00e9rer toutes les colonnes d'investissements.\");\n      }\n\n      const data = new google.visualization.DataTable();\n      data.addColumn('string', 'Ann\u00e9e');\n      data.addColumn('number', 'Grands Projets');\n      data.addColumn('number', 'Grands Projets r\u00e9gionaux');\n      data.addColumn('number', 'Part des grands projets dans le total des investissements de SNCF R\u00e9seau');\n\n      rows.forEach(r => {\n        const year = String(r[idxYear]).trim();\n        if (!\/^\\d{4}$\/.test(year)) return;\n\n        const gp = parseNumberFR_AftInvestReseauDev(r[idxGP]);\n        const pr = parseNumberFR_AftInvestReseauDev(r[idxPR]);\n        const conformite = parseNumberFR_AftInvestReseauDev(r[idxConformite]);\n        const renouv = parseNumberFR_AftInvestReseauDev(r[idxRenouvPerf]);\n        const fonc = parseNumberFR_AftInvestReseauDev(r[idxFoncAutres]);\n        const indus = parseNumberFR_AftInvestReseauDev(r[idxIndus]);\n\n        if (![gp, pr, conformite, renouv, fonc, indus].every(Number.isFinite)) return;\n\n        const total = gp + pr + conformite + renouv + fonc + indus;\n        const ratio = total > 0 ? (gp + pr) \/ total : 0;\n\n        data.addRow([year, gp, pr, ratio]);\n      });\n\n      return data;\n    }\n\n    function drawChart_AftInvestReseauDev(data) {\n      const options = {\n        isStacked: true,\n        seriesType: 'bars',\n        series: {\n          0: { targetAxisIndex: 0 },\n          1: { targetAxisIndex: 0 },\n          2: { type: 'line', targetAxisIndex: 1 }\n        },\n        vAxes: {\n          0: { title: 'Montant (M\u20ac)', viewWindow: { min: 0 } },\n          1: { title: 'Part des grands projets dans les investissements de SNCF R\u00e9seau', format: 'percent', viewWindow: { min: 0, max: 1 } }\n        },\n        legend: { position: 'top' },\n        chartArea: { left: 70, right: 70, top: 50, height: '70%' },\n        tooltip: { isHtml: true }\n      };\n\n      const chart = new google.visualization.ComboChart(\n        document.getElementById('chartAftInvestReseauDev')\n      );\n      chart.draw(data, options);\n      window.addEventListener('resize', () => chart.draw(data, options));\n    }\n\n    \/\/ ======== MAIN ========\n    google.charts.load('current', { packages: ['corechart'] });\n    google.charts.setOnLoadCallback(async () => {\n      try {\n        const csv = await fetchCSV_AftInvestReseauDev(DATA_URL_AftInvestReseauDev);\n        const { headers, rows } = parseCSV_AftInvestReseauDev(csv);\n        const data = buildDataTable_AftInvestReseauDev(headers, rows);\n        drawChart_AftInvestReseauDev(data);\n      } catch (err) {\n        document.getElementById('chartAftInvestReseauDev').innerHTML =\n          '<p style=\"color:#b00\">Erreur lors du chargement ou du parsing des donn\u00e9es.<br>' +\n          'V\u00e9rifiez le chemin du fichier, les en-t\u00eates et les autorisations CORS.<\/p>';\n        console.error(err);\n      }\n    });\n  <\/script>\n","protected":false},"excerpt":{"rendered":"<p>Acteur central du syst\u00e8me ferroviaire fran\u00e7ais, SNCF R\u00e9seau porte une responsabilit\u00e9 strat\u00e9gique : financer, entretenir et moderniser un r\u00e9seau qui conditionne \u00e0 la fois la mobilit\u00e9 des voyageurs, la comp\u00e9titivit\u00e9 du fret et la transition \u00e9cologique du pays. Derri\u00e8re cette mission se cache une \u00e9quation \u00e9conomique complexe, o\u00f9 se croisent recettes r\u00e9gul\u00e9es, contraintes de performance [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"ocean_post_layout":"","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"","ocean_second_sidebar":"","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"","ocean_custom_header_template":"","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"","ocean_menu_typo_font_family":"","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"","footnotes":""},"class_list":["post-373","page","type-page","status-publish","hentry","entry"],"_links":{"self":[{"href":"https:\/\/huguesg.fr\/site\/index.php\/wp-json\/wp\/v2\/pages\/373","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/huguesg.fr\/site\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/huguesg.fr\/site\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/huguesg.fr\/site\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/huguesg.fr\/site\/index.php\/wp-json\/wp\/v2\/comments?post=373"}],"version-history":[{"count":28,"href":"https:\/\/huguesg.fr\/site\/index.php\/wp-json\/wp\/v2\/pages\/373\/revisions"}],"predecessor-version":[{"id":634,"href":"https:\/\/huguesg.fr\/site\/index.php\/wp-json\/wp\/v2\/pages\/373\/revisions\/634"}],"wp:attachment":[{"href":"https:\/\/huguesg.fr\/site\/index.php\/wp-json\/wp\/v2\/media?parent=373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}