I would like to replace one character in a string with an uppercase of the same character. Is there an elegant way to do this? Eg I have 'Donald Mcdonald' and I would like to uppercase the first 'd' in 'Mcdonald' so I end up with 'McDonald'

The string.replace function only gives the option to replace first or all. If I use the code below it obviously won't work.

if(name.containsIgnoreCase(' mc')){
    integer mc = name.indexOfIgnoreCase(' mc') + 3;
    name = name.replaceFirst(name.mid(mc, 1), name.mid(mc,1).toUpperCase());

Apex doesn't really support that. Strings are as in Java, immutable objects, so you can only create modified copies, but not update the original. It has to do with Java's String Pool. So, replaceFirst is probably appropriate in your case. Notably, the first parameter is actually a regular expression, so you can target exactly what you want to with some practice.

For example:

String name = 'old mcdonald';
String mc = '(?i)( mcd)';
name = name.replaceFirst(mc, ' McD');

You can also use String.split with similar effect, although this is probably the easiest way to get what you're looking for.

If you don't know what you're looking for, the following may also help:

Pattern mcprefix = Pattern.compile('(?i)( ma?c)(i|d|k)');
Matcher m = matcher.match(name);
while(m.find()) {
  String g1 = m.group(1), g2 = m.group(2);
  name = name.replaceFirst(mc, g1.capitalize()+g2.captialize());

Which should give you a pretty good algorithm to start from.

  • Thing is I don't know what comes after the 'mc' - could be 'mcintyre', 'mckenzie' etc, so I have to get the char after the mc, capitalise it and then do the replaceFirst I guess. Need to sort out names are are entered in all lower or uppercase to be titlecase, but to cater for these anomalies as best possible (mc, mac) – Irene Jul 21 '20 at 1:34
  • @Irene I see. You could use Pattern.match to determine the letter, then use that instead. I'll edit. – sfdcfox Jul 21 '20 at 2:23
  • I got an error but managed to fix it (2nd line: Matcher m = mcprefix.matcher(name); ) I changed the regex too and am using this now: (?i)( ?ma?c)(\p{L}) so it'll catch whatever alpha character is after the mc/mac, but I don't know how many matches there are, and I don't think there's a way I can loop through them, is there? So if my string is 'mckenzie mcewan macdonald' I'd have 3 matches. I suppose I'd have to split the string and sort each one out and then join them again? – Irene Jul 21 '20 at 2:57
  • I posted my final code - am happy for you to edit yours with this and then I can credit you with the solution. – Irene Jul 21 '20 at 3:25

Thanks to @sfdcfox for the platform to build on. This is what I eventually ended up with which works perfectly for a string with multiple occurrences.

Pattern mcprefix = Pattern.compile('(?i)( ?ma?c)(\\p{L}+|\\P{L}+)');
list<string> names = name.split(' ');
list<string> fixednames = new list<string>();
for(string n : names){
    Matcher m2 = mcprefix.matcher(n);
    while(m2.find()) {
      String g1 = m2.group(1), g2 = m2.group(2);
      Integer start = n.indexOf(g1 + g2);
      if (start == 0 || n.substring(start - 1, start).isWhitespace())
        n = n.replaceFirst(g1 + g2, g1 + g2.capitalize());
name = String.join(fixednames, ' ');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.