claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

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

Open pscheit opened this issue 6 months ago • 6 comments

Environment

  • Platform (select one):
    • [x] Anthropic API
    • [ ] AWS Bedrock
    • [ ] Google Vertex AI
    • [ ] Other:
  • 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’)

pscheit avatar Jun 12 '25 04:06 pscheit

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

daliusd avatar Sep 27 '25 17:09 daliusd

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.

github-actions[bot] avatar Dec 09 '25 10:12 github-actions[bot]

This is still occurring for me.

tomtaylor avatar Dec 09 '25 11:12 tomtaylor

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

daliusd avatar Dec 09 '25 11:12 daliusd

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 avatar Dec 12 '25 12:12 BigBenJr

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

BigBenJr avatar Dec 12 '25 12:12 BigBenJr