{
  "slug": "csv-column-number-formatter",
  "name": "gizza-ai/csv-column-number-formatter",
  "version": "0.1.0",
  "title": "CSV Column Number Formatter — Fix Decimals, Rounding and Grouping — gizza.ai",
  "description": "Give a CSV column one uniform number format: fixed decimals, a rounding mode, thousands grouping, sign style and units. Free, runs entirely in your browser.",
  "tags": [
    "csv number formatter",
    "format csv column numbers",
    "round csv column decimal places",
    "add thousands separator to csv",
    "fixed decimal places csv",
    "csv currency formatting",
    "banker's rounding csv",
    "european number format csv"
  ],
  "category": "data",
  "urls": {
    "page": "https://gizza.ai/tools/csv-column-number-formatter/",
    "markdown": "https://gizza.ai/tools/csv-column-number-formatter/index.md",
    "descriptor": "https://gizza.ai/tools/csv-column-number-formatter/tool.json",
    "deep_link_example": "https://gizza.ai/tools/csv-column-number-formatter/?data=sku%2Cprice%2Cweight%0AA1%2C1234.5%2C0.5%0AB2%2C7%2C12.25&columns=price%2C3%2C5-7&decimals=2&rounding=half_up&notation=standard&grouping=none&group_separator=comma&decimal_separator=period&sign=auto&prefix=%24&suffix=%20kg&input_decimal=auto&non_numeric=keep&has_header=true&delimiter=auto&quote_style=minimal&output=csv"
  },
  "cli": "gizza tool csv-column-number-formatter \"sku,price,weight\nA1,1234.5,0.5\nB2,7,12.25\"",
  "tool": {
    "description": "Apply ONE uniform numeric format to the cells of the CSV columns you pick, and get the table back. decimals fixes how many fractional digits every value carries (0 for whole numbers; NEGATIVE values round to tens, hundreds or thousands instead), and rounding picks how a dropped digit resolves: half_up (the spreadsheet ROUND, the default), half_down, half_even (banker's), ceil, floor or truncate. Rounding runs on the DIGIT STRING parsed out of the cell, never on a binary float, so 1.005 at two places is 1.01 rather than the 1.00 a naive multiply-and-round returns. notation renders the value as standard digits, compact K/M/B/T, scientific, or percent (times 100 with a % sign). grouping is none (the default, which keeps the column machine-readable), thousands (1,234,567) or indian (12,34,567), with group_separator and decimal_separator choosing the marks — so a European 1.234,56 column can be read and rewritten as 1,234.56 or vice versa. sign is auto, always, except_zero, never, space (aligns a column) or parens (accounting negatives); prefix and suffix wrap the number with a currency symbol or a unit. Input cells may be messy: currency symbols, group marks, accounting parentheses, a trailing minus, and scientific notation are all parsed, and input_decimal fixes which of '.' and ',' is the decimal mark. columns is blank for every column, or a mix of header names, 1-based indices and '2-4' ranges; the header row is never reformatted while has_header is on. non_numeric decides whether a cell like 'n/a' is kept, blanked, or an error; an empty cell is always left empty. delimiter is 'auto' or a named/single character, quote_style is minimal, always or non_numeric, and output is 'csv' (the rewritten table), 'changed' (header plus only the rows that changed) or 'report' (a per-column column,cells_formatted,cells_unchanged,non_numeric audit with a TOTAL row). Max 5,000,000 bytes. Runs entirely in the sandbox; nothing is uploaded.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "columns": {
          "default": "",
          "description": "Which columns to reformat. Blank (the default) or '*' means every column. Otherwise a comma-separated list of header names ('price'), 1-based indices ('2'), and inclusive index ranges ('2-4') — mixed freely, e.g. 'price,3,5-7'. Names are matched exactly first, then case-insensitively. Cells in unselected columns are copied through byte-for-byte.",
          "type": "string"
        },
        "data": {
          "description": "The CSV/delimited table to reformat, as text. It is parsed first, so each number is read from a decoded cell value and the rewritten table keeps its row order, column count and delimiter; output quoting is re-derived, so a grouped value such as 1,234.00 is re-quoted automatically. Max 5,000,000 bytes.",
          "type": "string"
        },
        "decimal_separator": {
          "default": "period",
          "description": "The character written before the fractional digits on OUTPUT: 'period' (default, 1234.56) or 'comma' (1234,56). This is independent of input_decimal, so the tool can read a European column and write a US one, or the reverse.",
          "enum": [
            "period",
            "comma"
          ],
          "type": "string"
        },
        "decimals": {
          "default": 2,
          "description": "How many digits to keep after the decimal mark; every value is padded or rounded to exactly this many, so a column lines up. 0 gives whole numbers. NEGATIVE values round to the left of the decimal point instead: -2 rounds 12,345 to 12300, -3 to the nearest thousand. Range -9 to 15, default 2.",
          "maximum": 15,
          "minimum": -9,
          "type": "integer"
        },
        "delimiter": {
          "default": "auto",
          "description": "Field separator: 'auto' (default) sniffs it from the first line, counting candidates outside quotes with comma winning a tie; or give a name ('comma', 'tab', 'semicolon', 'pipe') or any single character. The output is written with the same separator.",
          "type": "string"
        },
        "group_separator": {
          "default": "comma",
          "description": "The character placed between digit groups when grouping is on: 'comma' (default, 1,234,567), 'period' (1.234.567 — the European convention, pair it with decimal_separator=comma), 'space', 'thin_space' (U+202F, the typographic choice), 'apostrophe' (the Swiss 1'234'567), or 'underscore'. Ignored when grouping is 'none'.",
          "enum": [
            "comma",
            "period",
            "space",
            "thin_space",
            "apostrophe",
            "underscore"
          ],
          "type": "string"
        },
        "grouping": {
          "default": "none",
          "description": "Digit grouping for the integer part. 'none' (default) writes no separators, which keeps the column machine-readable in the next tool. 'thousands' groups by three from the right (1,234,567). 'indian' uses the South Asian pattern of three then twos (12,34,567). A grouped value containing the delimiter is quoted on output automatically.",
          "enum": [
            "none",
            "thousands",
            "indian"
          ],
          "type": "string"
        },
        "has_header": {
          "default": true,
          "description": "When true (default) row 1 is a header: its names can be used in 'columns' and it is never reformatted, so a column called 2024 stays 2024. Turn it off for a headerless table — every row is then data and columns must be given as indices or ranges.",
          "type": "boolean"
        },
        "input_decimal": {
          "default": "auto",
          "description": "Which character the INCOMING cells use as their decimal mark. 'auto' (default) decides per cell: when both '.' and ',' appear the last one wins, a lone '.' is a decimal point, and a lone ',' followed by exactly three digits is read as grouping ('1,234' is one thousand two hundred and thirty-four). 'dot' forces 1,234.56 and 'comma' forces 1.234,56 — use one of those when a column of ambiguous values must be read consistently.",
          "enum": [
            "auto",
            "dot",
            "comma"
          ],
          "type": "string"
        },
        "non_numeric": {
          "default": "keep",
          "description": "What to do with a selected cell that is not a number, such as 'n/a' or 'pending'. 'keep' (default) copies it through untouched; 'blank' replaces it with an empty cell; 'error' stops and reports the row, column and value. An EMPTY cell is always left empty in every policy — a missing value is not a zero.",
          "enum": [
            "keep",
            "blank",
            "error"
          ],
          "type": "string"
        },
        "notation": {
          "default": "standard",
          "description": "The shape of the rendered number. 'standard' (default) is plain positional digits. 'compact' scales to K/M/B/T and appends the unit letter (1234567 becomes 1.23M). 'scientific' renders one digit before the decimal mark plus an exponent (1.23e+6). 'percent' multiplies by 100 and appends '%' (0.452 becomes 45.2%). decimals applies to the rendered mantissa in every case.",
          "enum": [
            "standard",
            "compact",
            "scientific",
            "percent"
          ],
          "type": "string"
        },
        "output": {
          "default": "csv",
          "description": "What to return: 'csv' (default) is the whole table with the format applied; 'changed' is only the rows whose selected cells actually changed, plus the header, for reviewing a format before committing to it; 'report' is a per-column audit table 'column,cells_formatted,cells_unchanged,non_numeric' with a TOTAL row and no data at all.",
          "enum": [
            "csv",
            "changed",
            "report"
          ],
          "type": "string"
        },
        "prefix": {
          "default": "",
          "description": "Text placed immediately before each formatted number, inside the sign — '$' gives -$1,234.00 and, with sign='parens', ($1,234.00). Blank by default. It is inserted verbatim, so add your own trailing space if you want one.",
          "type": "string"
        },
        "quote_style": {
          "default": "minimal",
          "description": "How the rewritten table is quoted. 'minimal' (default) quotes only fields that need it — a grouped value whose separator is the delimiter is re-quoted automatically. 'always' quotes every field; 'non_numeric' quotes every field that is not a number.",
          "enum": [
            "minimal",
            "always",
            "non_numeric"
          ],
          "type": "string"
        },
        "rounding": {
          "default": "half_up",
          "description": "How a digit that has to be dropped is resolved. 'half_up' (default) is the spreadsheet ROUND: 2.5 becomes 3 and -2.5 becomes -3. 'half_down' sends an exact half toward zero; 'half_even' is banker's rounding (2.5 becomes 2, 1.5 becomes 2); 'ceil' always goes toward +infinity; 'floor' toward -infinity; 'truncate' just drops the extra digits. Rounding runs on the digit string that was typed, not on a binary float, so 1.005 at 2 places is 1.01.",
          "enum": [
            "half_up",
            "half_down",
            "half_even",
            "ceil",
            "floor",
            "truncate"
          ],
          "type": "string"
        },
        "sign": {
          "default": "auto",
          "description": "How the sign is shown. 'auto' (default) writes '-' on negatives only. 'always' adds '+' to zero and positives; 'except_zero' adds '+' to positives but leaves zero bare; 'never' drops the sign entirely and writes the magnitude; 'space' puts a blank where the '+' would go so a column of values lines up; 'parens' is the accounting style that wraps negatives in parentheses, as in (1,234.00). A value that rounds to zero never keeps a minus sign.",
          "enum": [
            "auto",
            "always",
            "except_zero",
            "never",
            "space",
            "parens"
          ],
          "type": "string"
        },
        "suffix": {
          "default": "",
          "description": "Text placed immediately after each formatted number, such as ' kg', ' ms' or ' USD'. Blank by default and inserted verbatim, so include the leading space yourself if you want one. For percentages prefer notation='percent', which also multiplies by 100.",
          "type": "string"
        }
      },
      "required": [
        "data"
      ],
      "type": "object"
    }
  }
}