east825
east825

Reputation: 909

How change all uppercase words to lowercase, but exclude string literals in Vim

I got rather long sql script where all keyword are uppercase. I want to change them to lowercase, but preserve exact values of string literals and my own identifers.
For example, in this text:

KEYWORD BEFORE 'SOME STRING LITERAL' KEYWORD AFTER
mixedCaseValue  
MY_OWN_VARAIBLE
UGLY APPERCASE KEYWORDS, other text

I want only 'KEYWORD BEFORE', 'KEYWORD AFTER' and last 'UGLY UPPERCASE KEYWORDS' to be lowercase and all other left intact.
If I use something like this :%s/\<\u\+\>/\L&/g, text inside quotes on the first line is also affected.

Do you have any ideas?

Upvotes: 1

Views: 2646

Answers (3)

David Pope
David Pope

Reputation: 6587

My inner vim-loving soul cringes to write these, but...

If this is something you don't have to do frequently, you might just brute-force it by appending the c flag onto your substitution command to prompt for confirmation of each change; you should be able to blow through a lot of script quickly, if you can put up with the tedium. It might be faster this way (in the short term) than by spending time crafting a good substitution command.

Alternatively, if there are only a handful of string literals that need to not be touched, change those to some other string so the global substitution doesn't change them, do the global substitution, and then change them back. Also gross but effective.

Ugh, I feel dirty.

Upvotes: 1

ib.
ib.

Reputation: 28944

Assuming that string literals do not span over multiple lines, and that there is no syntax for escaping single quotes inside string literals, I would use the following substitution command.

:%s/\%(^\%([^']*'[^']*'\)*\)\@<=[^']\+/\=substitute(submatch(0),'\<\u\+\>','\L&','g')/g

Upvotes: 1

Birei
Birei

Reputation: 36262

One way:

:%v/'/s/\(^\|\s\)\@<=\u\+\(\s\|,\)\@=/\L&/g

Explanation:

%                      # Range: All file.
v/pattern/command      # Apply command to all lines that doesn't match pattern
'                      # The pattern, so apply substitution to lines that doesn't have it.
s/string/replacement/  # Replacement command.
\(^\|\s\)\@<=          # Zero-width preceding match: Beginning of line or a space.
\u\+                   # One or more alphabetic uppercase letters.
\(\s\|,\)\@=           # Zero-width positive match: Space or comma.
\L&                    # Lowercase the string matched
/g                     # Apply globally: Many times for each line.

Result:

'SOME STRING LITERAL'  
mixedCaseValue  
MY_OWN_VARAIBLE
ugly appercase keywords, other text

Upvotes: 2

Related Questions