Do not double-click the CSV an AI assistant just generated. Seeing 0007 and what looks like four columns in a text editor does not establish what Excel will import. A comma inside a product name can become a separator, a newline in a note can become another record, and formula-like content may be interpreted by a spreadsheet. Inspect the file before deciding how to import it.
This tutorial is for operations, product and development staff who move AI output into Excel. We use three fictional products, a read-only Python standard-library check, then an Excel import preview to confirm encoding and column types. No additional CSV plugin is needed. Excel licensing depends on your existing access, and interfaces vary by version. The script passed 21 in-memory checks on Python 3.12.14; no Excel interface was operated and no real business data was sent to a model.
Agree on four columns before generating the file
The header is exactly sku,name,price,note, including order and case. A SKU contains four ASCII digits, must be unique, and may have leading zeroes. A name cannot consist entirely of whitespace. A price is a nonnegative plain decimal with at most two fractional digits: no currency symbol, thousands separator or scientific notation. Notes may contain commas, double quotes and newlines. Negative refunds require a different specification rather than an improvised exception.
Use an approved assistant such as Claude or Microsoft Copilot to draft and explain text, not guarantee import results. This small fictional sample does not require premium model features or uploading a customer list. Save the following as demo.csv using UTF-8 in a text editor. The checker accepts UTF-8 with or without a BOM.
sku,name,price,note
0007,"Cup, blue",19.90,"first line
second line"
0008,Notepad,9.00,"He said ""ship today"""
0009,Storage box,12.50,ordinary note
There are three data records, not four: the first note occupies two physical lines. Double quotes enclose the comma-containing name, and doubled double quotes represent literal quotes inside a field. Do not save Markdown fences or introductory explanation as part of the file. Physical line count and parsed record count are different measurements.
Ask for a small sample, not ten thousand rows
Return plain CSV without Markdown fences or explanation. Use exactly sku,name,price,note as the header. SKU must be four unique ASCII digits with leading zeroes preserved; name must be nonempty; price must be a nonnegative decimal with at most two fractional digits. Produce three fictional rows covering an embedded comma, double quotes and a newline in a note. Apply CSV quoting correctly. Do not emit formulas, link formulas or extra columns. In a separate subsequent reply, explain the expected record count and fields; do not put that explanation into the CSV.
A prompt is not a security filter. The assistant might add a column, omit quotes or turn an identifier into a number. Check the small sample completely before processing a business copy. Four-digit SKUs are only this exercise's rule. If your real identifiers allow letters or longer numbers, revise both the specification and its negative tests.
Run a local check that reports positions without rewriting data
Save the following as check_csv.py. Python's csv module handles quoted fields and embedded newlines; splitting on commas or physical lines is not a substitute. The program reads at most 1,000,001 bytes to reject samples larger than 1,000,000 bytes, and accepts at most 10,000 data records. It does not modify files, access the network or print original cell contents.
import csv, io, json, re, sys, unicodedata
HEADER = ["sku", "name", "price", "note"]
LIMIT = 1_000_000
def inspect(raw):
def failure(code):
return {"records": 0, "issues": [[0, "file", code]]}
if len(raw) > LIMIT:
return failure("TOO_LARGE")
try:
text = raw.decode("utf-8-sig")
except UnicodeDecodeError:
return failure("ENCODING")
try:
rows = list(csv.reader(io.StringIO(text, newline=""), strict=True))
except csv.Error:
return failure("CSV_PARSE")
if not rows or rows[0] != HEADER:
return failure("HEADER")
if len(rows) > 10001:
return failure("TOO_MANY_RECORDS")
issues, seen = [], set()
for number, row in enumerate(rows[1:], 1):
if len(row) != 4:
issues.append([number, "record", "COLUMN_COUNT"])
continue
for field, value in zip(HEADER, row):
probe = unicodedata.normalize("NFKC", value).lstrip()
if (probe.startswith(("=", "+", "-", "@"))
or value.startswith(("\t", "\r", "\n"))
or "\x00" in value):
issues.append([number, field, "REVIEW_PREFIX"])
sku, name, price, note = row
if not re.fullmatch(r"[0-9]{4}", sku):
issues.append([number, "sku", "SKU_FORMAT"])
if sku in seen:
issues.append([number, "sku", "DUPLICATE"])
seen.add(sku)
if not name.strip():
issues.append([number, "name", "EMPTY"])
if not re.fullmatch(r"[0-9]+(?:\.[0-9]{1,2})?", price):
issues.append([number, "price", "PRICE_FORMAT"])
return {"records": len(rows) - 1, "issues": issues}
if __name__ == "__main__":
try:
with open(sys.argv[1], "rb") as source:
report = inspect(source.read(LIMIT + 1))
except (OSError, IndexError):
report = {"records": 0, "issues": [[0, "file", "INPUT_ERROR"]]}
print(json.dumps(report, ensure_ascii=True))
raise SystemExit(1 if report["issues"] else 0)
From the files' directory, run python check_csv.py demo.csv, or python3 on systems using that command. In PowerShell, inspect $LASTEXITCODE afterward. The sample should produce {"records": 3, "issues": []} with exit code 0; reported problems produce exit code 1. Each issue contains the data-record number, field and error code. Record numbers start after the header and are not text-editor line numbers. File-level errors use number 0.
COLUMN_COUNT means the parsed record does not contain four fields; CSV_PARSE means the parser rejected the input; ENCODING indicates invalid UTF-8; and DUPLICATE marks a repeated SKU. Strict parsing does not prove compliance with every CSV dialect. Header, column and business checks remain separate. A header-only batch reports zero records: even without formatting issues, it is not a three-record delivery.
CSV quoting does not eliminate formula risk
In a copy, replace a note with =1+1 and run only the checker, without opening the file in a spreadsheet. Expect REVIEW_PREFIX. The rule also flags formula-like prefixes after whitespace, certain full-width equivalents, and leading tabs or newlines. NFKC normalization is used only for inspection, never to change the original. A legitimate note beginning with a minus sign can also be flagged: a flag is not a verdict of malicious intent.
OWASP's CSV Injection guidance warns that spreadsheet applications can interpret certain prefixes as formulas and that saving and reopening files can change escaping behavior. This checker stops for review instead of silently adding quotes, removing equals signs or prefixing apostrophes. It is not a security certification covering every application, locale or bypass. Use an approved text-import process for untrusted material; an empty issue list is not a reason to dismiss security warnings.
Choose encoding and column types before loading into Excel
Keep the original untouched. Microsoft says UTF-8 CSV saved with a BOM can normally be opened directly; otherwise use an import route such as Data, Get Data, From File, From Text/CSV. Labels vary by version. In the preview, confirm UTF-8 and comma separation rather than repeatedly resaving the original to fix garbled text. Check that non-ASCII text, comma-containing names and multiline notes remain intact.
Set the SKU column to text instead of trusting automatic detection. If the import applies automatic type conversion, adjust it before loading so 0007 does not become 7. Whether prices become numeric values depends on your specification. These instructions follow Microsoft's encoding-import guidance; we did not test button locations in a particular Excel version. Correct encoding does not establish correct types or trustworthy content.
Deliver a checkable batch, not a claim that it is clean
A follow-up prompt can be precise: “The checker flags REVIEW_PREFIX for record 2, note. Explain possible causes without inventing data or changing product facts. List decisions requiring human review.” Share only rules, a redacted sample and error codes, not customer names, orders or complete financial records. After correcting a copy, rerun every check and inspect the Excel preview. An assistant saying “fixed” is not fresh execution evidence.
- Retain the original CSV, rule version and output provenance; edit a new copy.
- Confirm record and field counts, unique identifiers and price formatting. Sample both normal and flagged records.
- Handle formula-like content through the approved process, preserving leading zeroes and non-ASCII text.
- Record the actual exit code, check time, import settings and unresolved questions. Do not claim an Excel test that was not performed.
Larger batches also need source validation, resource limits, logging permissions and destination-system checks. This teaching script is not a production importer. If the starting point is a PDF table, our Docling tool page explains structured extraction. A CSV extracted from a PDF still needs validation; changing the upstream tool does not remove that requirement.