For a shell script used to automatically generate c++ code files, I have to split certain names apart for them to be formatted. I split them at a capital letter, but I do not want to split if there are multiple capital letters in sequence. For example:
I want this (and I get this):
ChanNameWordWrapMode -> Chan Name Word Wrap Mode
I want this:
ChanNameVAlign -> Chan Name VAlign
OSDSettings -> OSD Settings
But I get this:
ChanNameVAlign -> Chan Name V Align
OSDSettings -> O S D Settings.
The command I am using right now is:

`echo $string | sed 's/\([A-Z]\)/ \1/g' | sed 's/^ *//;s/ *$//'`

Can someone help with a sed command that does what I am asking? Thanks.

Dani AI

Generated

Nice thread. nailed the main rule: split on a lowercase-to-uppercase boundary. The missing piece is handling acronym runs without breaking them up, while still splitting before the final cap that starts a normal word (so OSDSettings -> OSD Settings, but VAlign stays intact).

You can do both with two substitutions in one sed run. Use POSIX classes for portability:

# BSD/macOS: -E ; GNU sed: -r or -E
sed -E 's/([[:lower:]])([[:upper:]])/\1 \2/g; s/([[:upper:]]{2,})([[:upper:]][[:lower:]])/\1 \2/g'

Why it works:

  • First s/// inserts a space between a lowercase and an uppercase (ChanName -> Chan Name).
  • Second s/// inserts a space only after a run of 2+ capitals when the next token looks like Cap+lowercase. That gives OSD Settings, but it does not touch VAlign because there is no place where 2+ capitals are immediately followed by Cap+lowercase inside VAlign.

If you already have inputs like "O S D Settings" (as mentioned later), normalize them first by collapsing spaces between adjacent single-letter capitals, then apply the splitter:

# collapse spaced acronyms: "O S D Settings" -> "OSD Settings"
sed -E ':a; s/\b([A-Z])\s+([A-Z])\b/\1\2/g; ta'

Tips:

  • Prefer [[:upper:]]/[[:lower:]] over A-Z/a-z if locale or non-ASCII might appear.
  • To stay strictly ASCII for code identifiers, run with LC_ALL=C.

Recommended Answers

All 6 Replies

In the ChanNameVAlign case you want to split at the transition from lowercase to uppercase:
s/\([a-z]\)\([A-Z]\)/\1 \2/g

In the OSDSettings, I don't see a non-contradictory criteria.

Thanks. I will try that, but the current regex does split OSDSettings into O S D Settings

Okay, I thought of something to try, but I can't seem to construct the regex. If I have a string of the format "O S D Settings" that I want to convert to "OSD Settings", I could just concatenate the capital letters that are followed by a space, right? How might I construct this Regex?

This is working part way:

sed 's/ \([A-Z]\) \([A-Za-z]*\)/\1/g'

However, when run on the string "O S D Settings", it returns "OS Settings" - it is only operating on the first instance of the regex. Any tips on how to make it work for the whole line?

concatenate the capital letters that are followed by a space

I can think only of a 3-step solution (which looks ugly, but possibly it can be improved):
- replace all wanted spaces with, say, underscores:
s/ \([A-Z][^ ]\)/_\1/g'
- remove all remaining spaces:
s/ //g
- restore wanted spaces:
s/_/ /g'

Something like that...

Well, you don't have to use three commands - you can use pipes to redirect the code:

echo $string | sed 's/ \([A-Z][^ ]\)/_\1/g' | sed 's/ //g' | sed 's/_/ /g'

Anyway, thanks. This works. Thanks for all the help.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.