Case converter
Convert text between camelCase, snake_case, kebab-case, Title Case and more, with locale-aware casing and line tools. Runs in your browser.
Case forms
- UPPERCASE
XMLHTTPREQUEST HANDLER FOR ISTANBUL CITY GUIDE - lowercase
xmlhttprequest handler for istanbul city guide - Title Case
Xmlhttprequest Handler For Istanbul City Guide - Sentence case
Xmlhttprequest handler for istanbul city guide - camelCase
xmlHttpRequestHandlerForIstanbulCityGuide - PascalCase
XmlHttpRequestHandlerForIstanbulCityGuide - snake_case
xml_http_request_handler_for_istanbul_city_guide - kebab-case
xml-http-request-handler-for-istanbul-city-guide - CONSTANT_CASE
XML_HTTP_REQUEST_HANDLER_FOR_ISTANBUL_CITY_GUIDE - dot.case
xml.http.request.handler.for.istanbul.city.guide
Line operations
XMLHttpRequest handler for istanbul city guideLines: 1
One word split, ten case forms
Changing the case of text looks like the simplest thing a program can do, and it is the source of a surprising number of real bugs. Part of the reason is that "case" is really two separate problems wearing one name. Turning text into UPPERCASE or lowercase is a character-by-character mapping defined by Unicode. Turning it into camelCase or snake_case is something else entirely: you first have to decide where the words are, and only then recase and rejoin them. This tool does both, shows every result at once, and — importantly — tells you which of the answers depend on a language setting.
The six programmer forms all come out of the same word split, so they can never disagree with each other. Its boundaries are these:
- A lowercase letter followed by an uppercase one starts a new word, which is what makes fooBar into foo and Bar.
- A run of capitals ends where the next word begins — that is, at the last capital before a lowercase letter. XMLHttpRequest becomes XML, Http and Request; IOError becomes IO and Error.
- A digit followed by a capital starts a new word, so html5Parser becomes html5 and Parser.
- Anything that is not a letter, digit or combining mark separates words: spaces, underscores, hyphens, dots, punctuation.
Digits otherwise stay attached to the word in front of them, which is why utf8 and address2 come through whole. That is a deliberate divergence from lodash, whose splitter treats every run of digits as a word of its own and turns utf8 into utf_8 — technically consistent, but not what anyone naming a variable meant.
The split is written with Unicode property escapes rather than an ASCII character class, so it is not confined to English. A Cyrillic identifier splits at its case boundaries exactly as a Latin one does. A script that has no case at all — Hebrew, Arabic, Chinese, Japanese, Korean — has no case boundaries to find, so those words split on separators only, which is the correct answer rather than a limitation.
Acronyms: two right answers
Once XMLHttpRequest has been split into XML, Http and Request, rejoining it as PascalCase raises a question with no single correct answer. Recase every word and you get XmlHttpRequest, which is what lodash produces and what Google's Java style guide asks for: treat an acronym as an ordinary word so the boundaries stay visible in names like ParseXmlDocument. Keep the run of capitals and you get XMLHttpRequest, which is the actual name of the browser API and the convention most of the DOM and much of .NET follows.
Both are used in real codebases, so the tool offers both and defaults to recasing. The option only affects camelCase and PascalCase — the other forms recase the whole word anyway, so XMLHttpRequest is xml_http_request and XML_HTTP_REQUEST either way.
One detail is fixed rather than optional: the first word of a camelCase name is always fully lowercased, even when it is an acronym. Keeping it would produce PascalCase, and half-keeping it would produce xMLHttpRequest, a form no style guide recommends and every reader stumbles over. So XMLHttpRequest becomes xmlHttpRequest with the option either way, while parseXMLDocument keeps its acronym in the middle when you ask it to.
The Turkish i, and why the locale is a choice
JavaScript has two uppercasing methods, and the difference between them has broken production systems. toUpperCase applies the locale-independent Unicode mapping: the letter i becomes I. toLocaleUpperCase applies a language's own rules, and in Turkish and Azerbaijani the uppercase of i is İ, the dotted capital, because those alphabets also contain a dotless ı whose capital is I. Uppercase a Turkish user's input with their own locale and compare it against a protocol keyword, and the comparison fails on a character that looks almost identical.
This is the single most common internationalisation bug in string handling, and it is invisible until it happens to you. So this tool never guesses. Its default is the locale-independent mapping, which is what identifiers, protocol tokens, HTTP headers and database keys need. Choosing a language switches to that language's rules — and whenever the choice changes a result, the tool shows the locale-independent answer alongside it, so you can see exactly what the language did.
'i'.toUpperCase() // 'I'
'i'.toLocaleUpperCase('tr') // 'İ' dotted capital
'I'.toLocaleLowerCase('tr') // 'ı' dotless lowercase
'ISTANBUL'.toLocaleLowerCase('tr') // 'ıstanbul'Three other languages change the answer, and the tool offers all of them. Lithuanian keeps a dot above the i when lowercasing a capital that carries another accent, so Ì becomes i followed by a combining dot and a combining grave rather than the single precomposed ì. Greek drops the tonos when uppercasing, so άνθρωπος becomes ΑΝΘΡΩΠΟΣ and not ΆΝΘΡΩΠΟΣ, because Greek does not write the accent on capitals. Azerbaijani shares Turkish's dotted and dotless i.
Two famous cases are *not* locale rules, and it is worth knowing which is which. The German ß uppercases to SS in every locale, because that is a Unicode SpecialCasing rule rather than a German one — which is also why the mapping is not reversible, and SS lowercases back to ss. And a Greek sigma at the end of a word lowercases to the final form ς rather than σ, everywhere: that is a contextual condition on the character's position, not a language setting. Both are visible in this tool with no locale chosen at all.
Title case and sentence case are mechanical here
Title Case in this tool capitalizes the first letter of every word and lowercases the rest. Sentence case capitalizes the first letter of the text and of every sentence after it, where a sentence ends at a full stop, exclamation mark, question mark or ellipsis followed by whitespace. Both lowercase the input first, which is what makes them useful on text that arrived SHOUTING.
Those are deliberately mechanical rules, and the alternative is worth explaining. English style guides define title case by which short words stay lowercase — and they disagree with each other about the list, about whether to capitalise the word after a colon, and about prepositions of four letters or more. Applying one of them here would mean shipping American newspaper conventions to readers writing Hebrew, Japanese or Turkish, where the concept does not transfer at all. Capitalising every word is predictable, explicable in every language, and easy to adjust by hand afterwards.
The whitespace condition in sentence case is what keeps 3.5 metres from turning into 3.5 Metres, since the full stop there is followed by a digit. It does not solve abbreviations: e.g. this still starts a false sentence, because knowing that "e.g." is not the end of one requires a list of that language's abbreviations. An apostrophe inside a word does not start a new word either, so it's capitalizes once and gives It's rather than It'S.
Sorting: alphabetical order or byte order
The line utilities trim, deduplicate, sort, reverse and number lines, and the sort raises the locale question a second time. Alphabetical order is a property of a language, not of Unicode. German files ä next to a, so a, ä, z. Swedish treats it as a distinct letter at the end of the alphabet, so a, z, ä. Both are correct in their own country, and the tool uses whichever locale you picked at the top of the page.
The other option is code-point order, which is what you want when the answer has to match something else. Comparing by code point is byte order in UTF-8, so it reproduces exactly what LC_ALL=C sort, git and most programming languages' default string comparison produce — every capital before every lowercase letter, so B sorts before a. Choose it when you are diffing against tool output; choose collation when a human is going to read the list.
Natural number ordering — item2 before item10 rather than after it — is a feature of collation, so it is only available with the alphabetical rule. Byte order has no concept of a number inside a string, and neither does the sort it is imitating, so offering the two together would promise something the output could not honour.
The operations run in a fixed order, and the order matters. Trimming happens before deduplicating, so two lines that differed only in trailing whitespace are recognised as the same line. Sorting happens before reversing, so reversing always means "reverse what I am looking at". Both the number of empty lines and the number of duplicates removed are reported, because a silent count is how you fail to notice that your list was not what you thought.
Where it runs
Everything happens in your browser. The case mappings come from the JavaScript engine's own Unicode implementation and the collation from Intl.Collator, so the answers agree with the runtime that will actually be processing your strings rather than with a table someone copied years ago. Nothing you paste is uploaded, stored or logged, which makes the tool safe to use on names, log lines and anything else you would rather not send to a server just to change its capitalisation.
Frequently asked questions
- Is my text sent to a server?
- No. Every conversion runs in your browser using the JavaScript engine's own Unicode case mappings, and nothing you paste is uploaded or logged.
- Why does picking Turkish show me two different results?
- Because Turkish changes the answer. Its alphabet has both a dotted and a dotless i, so the uppercase of i is İ rather than I. Whenever a locale changes a result the tool shows the locale-independent answer beside it, since that is the one identifiers and protocol tokens need.
- Should I use the locale-independent mapping or a language one?
- Use the locale-independent mapping for anything a machine will read: identifiers, HTTP headers, database keys, protocol tokens, filenames. Use a language mapping for text a person will read in that language. Mixing them up is the classic Turkish-i bug.
- Why is XMLHttpRequest converted to XmlHttpRequest?
- Because acronyms are recased by default, which is what lodash and several major style guides do. Turn on the acronym option to keep the run of capitals and get XMLHttpRequest back. It only affects camelCase and PascalCase, since the other forms recase every word anyway.
- Why does utf8 stay one word when lodash splits it?
- Because digits attach to the word in front of them here, so utf8 and address2 come through whole. A digit followed by a capital does start a new word, which is what splits html5Parser into html5 and Parser.
- Why does Title Case capitalise short words like "of" and "the"?
- Because the rule is mechanical on purpose. The English style guides disagree with each other about which short words stay lowercase, and their conventions do not transfer to the other languages this site serves. Capitalising every word is predictable and easy to adjust by hand.
- Why can I not use natural number order with code-point sorting?
- Natural ordering is a collation feature. Code-point order is byte order, which has no notion of a number inside a string — and neither does the LC_ALL=C sort it reproduces. Offering both together would produce output that no longer matched the tool it is imitating.
- Why does ß become SS even with no locale selected?
- Because that mapping is a Unicode SpecialCasing rule rather than a German-language rule, so it applies everywhere. It is also not reversible: SS lowercases to ss, not back to ß. The Greek final sigma works the same way — it depends on the letter's position, not on a locale.