[BUG] Edit tool cannot distinguish between straight and curved quotes in replacements

Status Closed — not planned
Maintainer reply None cached
Activity 11 comments · opened Jun 12, 2025 · closed Jan 15, 2026

Environment

  • Platform (select one):
  • [x] Anthropic API
  • [ ] AWS Bedrock
  • [ ] Google Vertex AI
  • [ ] Other: <!-- specify -->
  • Claude CLI version: 1.0.21 (Claude Code)
  • Operating System: Linux 5.15.167.4-microsoft-standard-WSL2
  • Terminal: WSL2

Bug Description

The Edit tool fails to properly handle Unicode character replacements when characters are visually similar but have different byte representations. Specifically, the tool cannot distinguish between straight quotes (U+0027 ') and curved quotes (U+2018 ‘ and U+2019 ’), returning "No changes to make: old_string and new_string are exactly the same" even when hex dumps show the characters have different byte sequences.

Steps to Reproduce

  1. Create a file containing text with straight quotes around a placeholder: '%s'
  2. Attempt to use the Edit tool to replace the straight quotes with curved quotes: ‘%s’
  3. The Edit tool will claim no changes are needed despite the Unicode characters being different
  4. Verify with hexdump -C that the characters have different byte representations:
  • Straight quotes: 27 (U+0027)
  • Curved quotes: e2 80 98 (U+2018) and e2 80 99 (U+2019)

Expected Behavior

The Edit tool should successfully replace the straight quotes with curved quotes, recognizing that they are different Unicode characters despite visual similarity.

Actual Behavior

The Edit tool returns "No changes to make: old_string and new_string are exactly the same" and fails to perform the replacement, even though the characters are demonstrably different at the byte level.

Additional Context

This issue was discovered while trying to standardize quote usage in documentation. The problem prevents proper Unicode character normalization and could affect any scenario where visually similar but distinct Unicode characters need to be replaced. The hex dump evidence clearly shows the characters are different:

  • Line with straight quotes: 27 25 73 27 ('%s')
  • Line with curved quotes: e2 80 98 25 73 e2 80 99 (‘%s’)

View original on GitHub ↗

11 Comments

daliusd · 11 months ago

Same problem with different quotes: https://github.com/anthropics/claude-code/issues/8234

github-actions[bot] · 8 months ago

This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.

tomtaylor · 8 months ago

This is still occurring for me.

daliusd · 8 months ago

I will just add: I suspect that this is model (Sonnet) bug as opencode.ai with Sonnet has the same problem

BigBenJr · 8 months ago

This is really annoying. Claude Opus 4.5 can see the difference between ' (straight apostrophe) (U+0027) and ’ (curly apostrophe) (U+2019) when reading, but cannot write curly apostrophes - they get somehow always converted to straight apostrophes

BigBenJr · 8 months ago

As a workaround here is a simple SKILL.md file content that teach Claude how to write properly curly apostrophe via a placeholder then a sed command:

---
name: curly-apostrophe
description: Auto-triggers when writing or editing text content that requires curly apostrophes. Teaches Claude to use placeholder and post-processing.
---

Curly Apostrophe Skill

Problem

Claude cannot directly write curly apostrophes (U+2019) through Write/Edit tools - they get converted to straight apostrophes (U+0027).

Solution

Use the placeholder __CURLY__ (double underscore + CURLY + double underscore), then post-process with bash.

---

Workflow

Step 1: Use Placeholder

When writing text that needs curly apostrophes, use __CURLY__ instead:

| Target text | Claude writes |
|----------|---------------|
| don’t | don__CURLY__t |
| it’s | it__CURLY__s |

Step 2: Post-Process

After each Write or Edit operation on a file containing __CURLY__, IMMEDIATELY run:

CURLY=$'\u2019' && sed -i "s/__CURLY__/${CURLY}/g" <filepath>

Step 3: Verify (Optional)

Verify the replacement worked by checking for e2 80 99 bytes:

hexdump -C <filepath> | grep "e2 80 99"

---

Example

# Before (what Claude writes)
Don__CURLY__t forget to check the student__CURLY__s answer.

# After running sed command
Don’t forget to check the student’s answer.

---

Important Notes

  1. Always run sed immediately after Write/Edit - do not batch multiple files
  2. The placeholder __CURLY__ is case-sensitive
  3. Works for any file type (.php, .html.twig, .md, .txt, etc.)
  4. The $'\u2019' bash syntax outputs UTF-8 bytes e2 80 99
  5. Do NOT run sed on this SKILL.md file - the placeholders here are documentation
ArtKoKo · 8 months ago

It's a good idea, but unfortunately, it requires explicitly stating in the prompt to preserve curly apostrophes, otherwise the skill won't trigger. Even worse, Claude sometimes considers it unnecessary to use because, as you pointed out, he can read and manipulate curly apostrophes internally, but when he uses Write, the curly apostrophes are replaced with straight apostrophes without his knowledge.

ArtKoKo · 8 months ago

For those interested, here are ready-to-use skills for correcting curly apostrophes, compatible with Mac (using Perl because there's a difference in arguments between BSD and GNU sed).

You need to extract the version you want (English or French or both) to ~/.claude/skills/ to activate it.

To encourage the skill to activate automatically, I recommend adding a directive like this to your ~/.claude/claude.md:

In English:
**Always use** the curly-apostrophe skill when editing text to preserve curved apostrophes and respect typographic conventions.

In French:
**Toujours utiliser** le skill apostrophes-courbes lors d'édition de texte afin de préserver les apostrophes courbes et pour respecter les conventions typographiques

Verify that it's working correctly by asking Claude to translate a file containing curly apostrophes, such as the reference.md file from the skill.

apostrophes-courbes.zip
curly-apostrophe.zip

github-actions[bot] · 7 months ago

This issue has been automatically closed due to 60 days of inactivity. If you're still experiencing this issue, please open a new issue with updated information.

pscheit · 7 months ago

ugh.. how is this automatically closed just because no one looked at it?

github-actions[bot] · 7 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.