String.prototype.capitalize=function(){return this.charAt(0).toUpperCase()+this.slice(1);};
String.prototype.followCase=function(b){
if(b==b.toUpperCase()){return this.toUpperCase();}
if(b==b.toLowerCase()){return this.toLowerCase();}
if(b==b.capitalize()){return this.capitalize();}
return this;
};
String.prototype.atRemoveAdd=function(index,n,string){
return this.substring(0,index)+string+this.substring(index+n,this.length);
};
String.prototype.matchIndex=function(re){
var a=[];
while((match=re.exec(this))!==null){
a.push({chars:match[0].length,index:match.index});
}
return a;
};
String.prototype.caseReplace=function(o,n){
for(var s=this,a=this.matchIndex(o),shift=0,i=0;i<a.length;i++){
var c=n.followCase(this.substring(a[i].index,a[i].index+a[i].chars));
s=s.atRemoveAdd(a[i].index+shift,a[i].chars,c);
shift+=c.length-a[i].chars;
}
return s;
};
My code from 2016 for the hall of shame where I realized today that caseReplace could just return this.replace(o,m=>n.followCase(m))
instead.