tsvkit.org
TSV Toolkit
Sample data Say hi →

Change Text Case in a TSV

UPPER · lower · Title · Sentence · camelCase · snake_case · kebab-case · runs in your browser

Case inconsistency is what turns one category into three. UK, uk, and Uk group separately, join separately, and dedupe separately, so a column that looks fine to a human quietly splits every count you run on it. This rewrites the case of whole columns — or just the header row, which is the usual fix before loading into a database that folds identifiers anyway.

case
Drop a .tsv file here, or
ready

How to use

  1. Paste or drop the file. The first row is treated as the header.
  2. Pick the target case. The first four are for prose; the last five are identifier styles for column names and keys.
  3. Choose the scope. Header row only is the common one — it renames columns without touching a single value.
  4. Limit to specific columns by name or 1-indexed position, comma-separated. Leave it blank for every column.
  5. Copy or download. The status line reports how many cells actually changed.

Prose case versus identifier case

UPPERCASE, lowercase, Title Case and Sentence case preserve the words and the spaces between them. Title Case capitalises after a space, hyphen, underscore, slash or opening bracket; Sentence case capitalises only after ., ! or ?. Both lowercase everything first, so NASA becomes Nasa — if your column holds acronyms, use these on the header row only.

snake_case, kebab-case, camelCase, PascalCase and CONSTANT_CASE are identifier styles. They split the value into words first — on any non-alphanumeric character, and also at a lowercase-to-uppercase boundary so orderTotal is read as two words — then rejoin without separators. That means punctuation is discarded, not converted. Applied to a sentence, Total (USD), net becomes total_usd_net. That is the right behaviour for a column name and the wrong behaviour for a value, which is why the scope selector defaults to data cells and you have to opt into the header.

Why the numbers checkbox is on by default

With leave numbers alone checked, any cell that reads as a plain number — digits, an optional sign, separators, an optional trailing % — is passed through untouched. Without it, the identifier styles would strip the decimal point out of 1.5 and give you 15. Uncheck it only if you know the column is text.

Everything else passes through byte-for-byte: empty cells stay empty, ragged rows stay ragged, and no row is added or removed. If you need the values normalised as well as re-cased — trailing spaces, non-breaking spaces — run trim whitespace first, then check the result with value counts to confirm the variants have actually collapsed into one.

FAQ

How do I fix column names before loading into Postgres?

Set the scope to header row only and the case to snake_case. Postgres folds unquoted identifiers to lowercase, so a header of Order Total becomes a column you can only reach as "Order Total" forever after. Converting to order_total up front avoids that. TSV to SQL will then generate clean DDL.

Does Title Case know about small words like "of" and "the"?

No — it capitalises every word. Proper editorial title case has language-specific rules about articles and prepositions that a general converter gets wrong more often than right, so this one is deliberately literal.

Can I convert one case style to another rather than from raw text?

Yes, that is exactly what the identifier styles do. user_id → camelCase gives userId; userId → kebab-case gives user-id. The word-splitting step handles both separators and case boundaries, so round-tripping between styles is lossless as long as the original had no punctuation you needed to keep.

What happens to non-English characters?

Uppercase, lowercase, Title and Sentence case use the browser's Unicode-aware case mapping, so accented Latin, Greek and Cyrillic convert correctly. The identifier styles split on non-alphanumeric ASCII, so accented characters survive but are not transliterated — Café Noir becomes café_noir, not cafe_noir.

Privacy

100% client-side. No upload. See the privacy policy.