Hi,
String.replace do not support function as second paramater,
Are there any plans to implement it
Here is my implementation (version 2 add support for replacement patterns):
I used to test it samples from MDN and:
Escape special symbols when EcmaScriptRegexpObject is created internally
static Regex StringReplacementPlaceHolders = new Regex("(\\$[`'&])|(\\$([1-9]{1}(?![0-9])|[0-9]{2}))", RegexOptions.Compiled);
static string FixRexExpSymbols(string pattern)
{
if (string.IsNullOrWhiteSpace(pattern))
{
return pattern ?? string.Empty;
}
string[] symbols = new[] { "\\", "[", "]", "^", "!", "|", "$", "?", "=", "{", "}", "+", "*", "(", ")" };
for (int i = 0, l = symbols.Length; i < l; i++)
{
pattern = pattern.Replace(symbols[i], "\\" + symbols[i]);
}
return pattern;
}
public object StringReplace(ExecutionContext aCaller, object aSelf, params object[] args)
{
MatchEvaluator lEvaluator = null;
string lNewValue = null; List<Match> lReplacementPlaceHolders = null;
var lSelf = Utilities.GetObjAsString(aSelf, aCaller) ?? string.Empty;
if (0 == args.Length)
{
return lSelf;
}
var arg_0 = Utilities.GetArg(args, 0);
if (null == arg_0 || Undefined.Instance == arg_0)
{
return lSelf;
}
var arg_1 = Utilities.GetArg(args, 1);
var lCallBack = arg_1 as EcmaScriptInternalFunctionObject;
if (null == lCallBack)
lNewValue = Utilities.GetObjAsString(arg_1, aCaller) ?? string.Empty;
if (!string.IsNullOrWhiteSpace(lNewValue))
{
lReplacementPlaceHolders = ExtractMatchPlaceHolders(lNewValue);
}
var lPattern = arg_0 as EcmaScriptRegexpObject;
if (lPattern == null && (lCallBack != null || lReplacementPlaceHolders != null))
{
lPattern = new EcmaScriptRegexpObject(aCaller.Global, FixRexExpSymbols(Utilities.GetObjAsString(arg_0, aCaller)), string.Empty);
}
if (lCallBack != null || lReplacementPlaceHolders != null)
{
if (lReplacementPlaceHolders == null)
{
object[] lCallBackArgs = null; int groups = 0;
lEvaluator = (Match match) =>
{
if (null == lCallBackArgs)
{
groups = match.Groups.Count;
lCallBackArgs = new object[groups + 2];
lCallBackArgs[lCallBackArgs.Length - 1] = lSelf;
}
for (var i = 0; i < groups; i++)
{
if (i == 0)
{
lCallBackArgs[lCallBackArgs.Length - 2] = match.Groups[i].Index;
}
lCallBackArgs[i] = match.Groups[i].Success ? (object)match.Groups[i].Value : Undefined.Instance;
}
var replacment = Utilities.GetObjAsString(lCallBack.CallEx(aCaller, aCaller.Global, lCallBackArgs), aCaller);
return replacment;
};
}
else
{
var text = new StringBuilder(); var lSelfIndex = 0;
lEvaluator = (Match match) =>
{
text.Length = 0;
var index = 0; var matchIndex = 0; var matchCount = match.Groups.Count;
foreach (var m in lReplacementPlaceHolders)
{
text.Append(lNewValue.Substring(index, m.Index - index).Replace("$$", "$"));//and remove escape symbols
switch (m.Value)
{
case "$`"://Inserts the portion of the string that precedes the matched substring.
text.Append(lSelf.Substring(0, match.Index));
break;
case "$'"://Inserts the portion of the string that follows the matched substring.
index = match.Index + match.Value.Length;
if (index < lSelf.Length)
{
text.Append(lSelf.Substring(index));
}
break;
case "$&":
text.Append(match.Groups[0].Value);
break;
default:
matchIndex = int.Parse(m.Value.Substring(1));
if (matchIndex < matchCount)
{
text.Append(match.Groups[matchIndex].Value);
}
break;
}
index = m.Index + m.Value.Length;
}
if (index < lNewValue.Length)
{
text.Append(lNewValue.Substring(index).Replace("$$", "$"));//and remove escape symbols
}
lSelfIndex = match.Groups[0].Index + match.Groups[0].Value.Length;
return text.ToString();
};
}
if (lPattern.GlobalVal)
{
lSelf = lPattern.Regex.Replace(lSelf, lEvaluator);
}
else
{
lSelf = lPattern.Regex.Replace(lSelf, lEvaluator, 1);
}
return lSelf;
}
else
{
if (lPattern == null)
{
// this will replace all occurrence
return lSelf.Replace(Utilities.GetObjAsString(arg_0, aCaller), lNewValue);
}
if (lPattern.GlobalVal)
return (lPattern.Regex.Replace(lSelf, lNewValue));
else
return (lPattern.Regex.Replace(lSelf, lNewValue, 1));
}
}
static List<Match> ExtractMatchPlaceHolders(string value)
{
var replacementPlaceHolders = (List<Match>)null;
foreach (Match m in StringReplacementPlaceHolders.Matches(value))
{
if (m.Success)
{
var i = m.Index; int count = 1; int result = 0;
while (i > 0)
{
--i;
if (value[i] != '$')
{
break;
}
++count;
}
Math.DivRem(count, 2, out result);
if (result != 0)
{
if (null == replacementPlaceHolders)
{
replacementPlaceHolders = new List<Match>();
}
replacementPlaceHolders.Add(m);
}
}
}
return replacementPlaceHolders;
}