To remove punctuation from a string in Java, call String.replaceAll("\\p{P}+", "") — the \p{P} Unicode property escape matches every character in the seven Unicode punctuation subcategories (Pc, Pd, Ps, Pe, Po, Pi and Pf) and replaceAll deletes them all in a single linear pass. Java developers reach for this pattern when sanitizing log lines, tokenizing text for natural-language processing, normalizing user input before storage, or preparing strings for full-text indexing. The regex flavor that ships with java.util.regex is Unicode-aware by default, which means \p{P} does what most hand-rolled [^a-zA-Z0-9 ] patterns cannot — it actually removes real punctuation instead of guessing at ASCII. Plain regex, however, has known weaknesses: contractions collapse, hyphenated compounds lose their hyphens, decimal points disappear from prices, and quote marks get treated identically to apostrophes. This guide walks through the Java code first, then shows how the Remove Punctuation tool catches the bugs a regex leaves behind.

The Seven Unicode Punctuation Subcategories
Unicode groups every code point into general categories, and punctuation lives in category P, which is split into seven subcategories. Pc is connector punctuation (the underscore and certain joining marks), Pd is dashes (the hyphen-minus, the en dash and the em dash), Ps is opening punctuation such as ( [ {, Pe is closing punctuation such as ) ] }, Po is "other" punctuation including commas, periods, colons, semicolons, question marks, exclamation marks and the ellipsis, Pi is initial quotes (the curly opening double, the guillemet, the opening single quote), and Pf is final quotes (the curly closing double, the right guillemet, the closing single quote). Java's regex engine reads these categories via the Unicode property escape \p{P} and treats them as a single character class — one pattern, seven subcategories, every punctuation mark Unicode knows about, including the full-width CJK marks such as the ideographic full stop (。). Each subcategory claim was verified character-by-character against the Unicode Character Database, not against an ASCII shortcut list. The \p{...} property syntax used here is documented in the Unicode character class escape reference; Java's java.util.regex and JavaScript share the same Unicode property names.
| Subcategory | Name | Examples |
|---|---|---|
| Pc | Connector punctuation | _ ‿ ⁔ |
| Pd | Dash | - – — |
| Ps | Opening punctuation | ( [ { |
| Pe | Closing punctuation | ) ] } |
| Po | Other punctuation | . , ; : ! ? … |
| Pi | Initial quote | " « ' " |
| Pf | Final quote | " » ' ' |
Three Java Approaches for Stripping Punctuation
Three Java approaches exist for stripping punctuation from a string. The first is String.replaceAll("\\p{P}+", "") — the recommended route. It is Unicode-aware, runs in a single linear pass, and the + quantifier collapses runs of punctuation so !!! becomes empty rather than leaving gaps between deleted marks. The second is String.replaceAll("\\p{Punct}+", "") — the POSIX-style character class. It matches a slightly different set (notably it includes the underscore and certain ASCII symbols) and is useful when you want ASCII punctuation only. The third is manual character iteration with Character.isLetterOrDigit() — slower, requires more code, and silently mishandles Unicode when letters exist outside ASCII ranges. Production Java code should reach for the first option unless the project specifically requires POSIX semantics.
Strip Punctuation From a Java String in One Line
Concretely, in a Java source file:
String input = "Hello, world! It's 2024 — and prices start at $9.99."; String stripped = input.replaceAll("\\p{P}+", "");
That single line removed every comma, exclamation mark, em dash and period in one pass. The dollar sign survived — symbols are not punctuation, and \p{P} does not match $. The apostrophe in It's was also stripped because plain \p{P}+ does not distinguish apostrophes from other Po characters. The em dash left two adjacent spaces because replaceAll substituted nothing for the matched code point; if you want single-space output, run a follow-up pass that collapses runs of spaces.
To keep contractions intact, a more careful regex adds lookbehind and lookahead assertions that require letters or digits on both sides of any mark:
String preserve = input.replaceAll("(?<![\\p{L}\\p{N}])\\p{P}+|(?<=[\\p{L}\\p{N}])\\p{P}+(?![\\p{L}\\p{N}])", "");
That regex protects word-internal marks — don't survives, state-of-the-art survives, 2020-2021 survives — while still stripping punctuation that floats at word boundaries or between spaces. There is one honest consequence of that rule: a trailing possessive like the dogs' bowls loses its apostrophe, because nothing follows it for the lookahead to match against. Documenting that in a comment is better than hiding it.
Symbols, Currency Signs, and Emoji Are Not Punctuation
The cleanest Java regex on the planet still has a sharp edge: it must not strip symbols that look like punctuation. Unicode places symbols in separate categories — Sm (math), Sc (currency), Sk (modifier), So (other) — so the dollar sign $, the plus sign +, the equals sign =, the copyright sign ©, the at sign @, the percent sign %, and every emoji you can paste from a phone are classified as symbols, not punctuation. A regex that uses [^a-zA-Z0-9 ] as a shorthand often deletes them too, and a developer who copies that pattern from a 2014 forum answer ends up with 1999 tax where the price used to be.
| Character | Unicode category | Matched by \p{P}? | Survives Java strip? |
|---|---|---|---|
| $ | Sc (currency symbol) | No | Yes |
| + | Sm (math symbol) | No | Yes |
| = | Sm (math symbol) | No | Yes |
| © | So (other symbol) | No | Yes |
| 😀 | So (other symbol) | No | Yes |
| , | Po (other punctuation) | Yes | No |
| . | Po (other punctuation) | Yes | No |
| — | Pd (dash) | Yes | No |
That distinction — punctuation versus symbol — is the whole reason a "remove punctuation from string java" question needs a careful answer.
Edge Cases That Trip Up Every Java Implementation
Three situations deserve explicit attention before the regex goes into production.
Numbers lose their decimal points and thousands separators. "9.99" becomes "999" and "1,000" becomes "1000" because the period and comma are punctuation. That is what removing punctuation means. If your code needs the pieces kept apart, replace each match with a single space — replaceAll("\\p{P}+", " ") — and then collapse runs of spaces; the digits become "9 99" rather than gluing together. For financial data the right answer is almost never to strip punctuation; parse the number instead.
Contractions and possessives collapse by default. "don't" becomes "dont", "it's" becomes "its", "James's book" becomes "Jamess book". The lookbehind/lookahead regex above fixes most cases, but a trailing possessive like "the dogs' bowls" still loses its apostrophe — nothing follows it, so the lookahead never fires. The Java file that documents this honestly is more useful than one that hides the consequence behind an undocumented if.
Line breaks and tabs are untouched. Java's \p{P} does not match \n or \t, so the shape of multi-line input survives. That matters when you are stripping punctuation from log lines before indexing.
Verify Your Java Output Against the Remove Punctuation Tool
Java code compiles slowly and runs locally, which makes it the wrong tool for the "I just want to see what the stripped text looks like" use case. The Remove Punctuation tool does the same Unicode-category check in the browser — it strips exactly the seven punctuation subcategories, leaves symbols and emoji untouched, and offers separate toggles to protect word-internal apostrophes and hyphens. Paste a sample string, decide whether contractions and compounds should keep their marks, click the button, and the counter at the bottom of the page reports exactly how many code points were deleted.
The tool is most useful as a verification step. Run your Java regex against the same input, paste the Java output through the tool with no protection toggles on, and confirm the counter stays at zero — that proves your regex removed the same set the Unicode standard defines. If the Java version loses characters the tool preserves, your regex is matching too much; if the tool loses characters the Java version preserves, your regex is missing one of the seven subcategories. The operation is idempotent, so processing the output a second time changes nothing.
For example, the input One, two. Three! contains exactly three punctuation marks: one comma, one period, one exclamation. The Java replaceAll("\\p{P}+", "") result is One two Three. Pasting that result back into the tool with no toggles on yields the same string and a removal count of zero. If the counter does not stay at zero, the regex matched more than the seven punctuation subcategories.
When to Use Java Code and When to Use the Tool
The split is straightforward. For anything that runs in production — a data pipeline, a log sanitizer, an indexing step — write Java; the regex is one line, the test is one line, and the audit trail lives in your repository. For anything faster to do with a click than to compile — a quick check on a paragraph pasted from a colleague, a sanity check on a regex before code review, a demonstration of what "removing punctuation" actually means to a non-engineer — use the tool. Java code is the right answer for repeatable work at scale; the browser tool is the right answer for the moment between reading this article and writing the regex.