Find and replace values with regex support
Find and replace values across your entire CSV or within specific columns. Supports exact match, case-insensitive match, and regular expressions.
Initializing in your browser…
A country column mixes "USA", "U.S.A.", and "United States" and you need one canonical value.
Operation
In "country": replace /U\.?S\.?A\.?|United States/ → "US"
Output
3,902 cells normalised across 1 column; other columns safe
Scoped, optionally regex-based replace lets you clean one column without the collateral damage of a global find-replace that would also rewrite unrelated text. The change count confirms the rule did what you expected before you export.
Find and replace values across your entire CSV or within specific columns. Supports exact match, case-insensitive match, and regular expressions.
CSV Search & Replace parses your file with PapaParse (skipEmptyLines enabled) and runs find-and-replace entirely in the browser. The search box supports four independent toggles that combine: in plain mode your term is run through a metacharacter escape (`.*+?^${}()|[]\` are backslash-escaped via `.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')`) so a dot or dollar sign is matched literally rather than as a regex token; turning on "Whole word" wraps that escaped term in `\b` word boundaries, so searching "cat" no longer matches inside "category"; "Case sensitive" controls whether the underlying RegExp uses the `i` flag (matching is always global, `g`); and "Use regex" hands your raw pattern straight to `new RegExp`, where you can use capture groups and reference them as `$1`, `$2` in the Replace field (replacement runs through String.prototype.replace). An invalid regex pattern is caught and simply yields zero matches instead of throwing.
You can scope a replace to a single column via the "Search In" selector (All Columns vs. Specific Column, picked by header name), which is useful for surgical edits like fixing a value only in an Email column without touching identical text elsewhere. As you type, a live counter shows the current position out of total matches (e.g. 1/12) with up/down chevron steppers that wrap around the list, and every match is highlighted yellow in the table with the active one ringed (ring-2 ring-yellow-300). You can then either Replace the one currently selected match (it splices the replacement in at that exact start/end offset using substring and advances to the next), or Replace All. When a replacement term is entered the preview table renders a diff per changed cell, the original struck through in red and the new value in green, before you commit anything.
Every Replace and Replace All snapshots the prior table state into a history stack capped at 20 entries (MAX_HISTORY = 20), each labeled with what it was about to change and a timestamp. You can Undo the most recent change, or open the History panel and restore to any earlier point in the stack, not just one level back. The preview table renders up to 50 data rows (with a "Showing 50 of N" footer for larger files) but replacements apply to the whole dataset. Export uses Papa.unparse to rebuild valid CSV and downloads it as `{originalname}_modified.csv`. On load, structural parse errors (Quotes/Delimiter type) abort with an error toast, while row field-count mismatches (FieldMismatch) only raise a warning and still load.
Load the built-in sample (employees with @oldcompany.com addresses; it prefills Search 'oldcompany' and Replace 'newcompany'). Set Search In to the Email column, review the green/red diff preview, then Replace All to rewrite every address while leaving other columns untouched.
To change the status 'Active' but not a value like 'Inactive', enable 'Whole word' so the term is wrapped in \b boundaries and only standalone occurrences match.
Enable 'Use regex', search a pattern such as (\w+)@(\w+) and use $1 / $2 in the Replace field to reorder or reformat the captured parts.
Yes. Select a specific column from the dropdown, or leave it on "All columns" for a global replace.
Yes. Use $1, $2, etc. in the replacement string to reference captured groups from your regex pattern.
Rows and columns are parsed and transformed in memory in your browser. No record ever reaches a server.