Skip to content

Keep a capitalised apostrophe name like "O'Neil" in one word [patch] - #103

Merged
matt-edmondson merged 4 commits into
mainfrom
fix/96-capitalised-apostrophe-names
Sep 29, 2026
Merged

matt-edmondson merged 4 commits into
mainfrom
fix/96-capitalised-apostrophe-names

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #96

What changed

When ReplaceNonAlphaNumericWithSpace drops an in-word apostrophe, "O'Neil" becomes "ONeil". SplitOnCaseChange then breaks that into "O Neil", so the word converted to o_neil, while "o'neil" and "O'NEIL" both gave oneil.

The fix takes the issue's first suggestion. A capital straight after the apostrophe is now lowercased when the letters around it are lowercase:

  • The letter after it decides, when there is one. O'Neil lowers the N. O'NEIL keeps it, so the word is still one all-caps word.
  • At the end of the word, the letter before the apostrophe decides. Don'T lowers the T. DON'T keeps it, which leaves the existing DON'T stop row unchanged.
  • The possessive-acronym path (API's, CEO's) runs first and is unchanged.
Input Pascal Snake Before (Snake)
O'Neil Oneil oneil o_neil
D'Angelo Dangelo dangelo d_angelo
Don'T stop DontStop dont_stop don_t_stop
O'NEIL Oneil oneil oneil (unchanged)

I didn't take the issue's second suggestion, splitting while the apostrophe is still present, because it would also change how ReplaceNonAlphaNumericWithSpace treats every other separator. That is a much wider change for the same result.

Testing

  • New rows next to the existing "o'neil" row in ApostropheWithinWordShouldNotSplitIt:
    • O'Neil, O’Neil, O'NEIL, D'Angelo, d'angelo and Don'T stop
    • O'Neil's car
    • McDonald's menu, which pins that a lowercase letter before the apostrophe is left alone
  • A new ACapitalisedApostropheNameShouldConvertLikeItsLowercaseSpelling test checks that each name converts like its lowercase spelling, and that x.ToTitleCase().ToSnakeCase() == x.ToSnakeCase().
  • With the source change reverted, 8 tests fail. With it, all 96 pass on net10.0.
  • dotnet build CaseConverter.sln builds every target (net10.0/9.0/8.0, netstandard2.0/2.1) with 0 warnings.

This touches the same loop as #101 (the İ/ı fix), right next to the line that PR changes. Whichever of the two merges second may need a trivial merge.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AtF6Ynq3K6Km6HSRHaKuX8


Generated by Claude Code

Dropping an in-word apostrophe left "O'Neil" as "ONeil", which the
case-change split then broke into "O Neil", so it converted to o_neil
while "o'neil" and "O'NEIL" both gave oneil. Lowercase a capital straight
after the apostrophe when the letters around it are lowercase: the letter
after it when there is one, otherwise the letter before the apostrophe.
"O'NEIL" and "DON'T" keep their capitals.

Fixes #96

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtF6Ynq3K6Km6HSRHaKuX8
… complexity in bounds

Sonar S3776 flagged ReplaceNonAlphaNumericWithSpace at 17 against the
allowed 15 after the nested if was added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtF6Ynq3K6Km6HSRHaKuX8
A ternary nested in the loop still costs Sonar's nesting increment, so
the method stayed at 17 against the allowed 15. Moving it into
LowercaseIf brings it back under the limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AtF6Ynq3K6Km6HSRHaKuX8
…ostrophe-names

# Conflicts:
#	CaseConverter/CaseConverter.cs
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A capitalised apostrophe name is split into two words: "O'Neil".ToSnakeCase() → "o_neil", but "o'neil" and "O'NEIL" → "oneil"

2 participants