func ReplaceAllSubmatchFunc(re *regexp.Regexp, b []byte, f func(s []byte) []byte) []byte { idxs := re.FindAllSubmatchIndex(b, -1) if len(idxs) == 0 { return b } l := len(idxs) ret := append([]byte{}, b[:idxs[0][0]]...) for i, pair := range idxs { // replace internal submatch with result of user supplied function ret = append(ret, f(b[pair[2]:pair[3]])...) if i+1 < l { ret = append(ret, b[pair[1]:idxs[i+1][0]]...) } } ret = append(ret, b[idxs[len(idxs)-1][1]:]...) return ret }
func builtinString_replace(call FunctionCall) Value { checkObjectCoercible(call.This) target := []byte(toString(call.This)) searchValue := call.Argument(0) searchObject := searchValue._object() // TODO If a capture is -1? var search *regexp.Regexp global := false find := 1 if searchValue.IsObject() && searchObject.class == "RegExp" { regExp := searchObject.regExpValue() search = regExp.regularExpression if regExp.global { find = -1 } } else { search = regexp.MustCompile(regexp.QuoteMeta(toString(searchValue))) } found := search.FindAllSubmatchIndex(target, find) if found == nil { return toValue_string(string(target)) // !match } { lastIndex := 0 result := []byte{} replaceValue := call.Argument(1) if replaceValue.isCallable() { target := string(target) replace := replaceValue._object() for _, match := range found { if match[0] != lastIndex { result = append(result, target[lastIndex:match[0]]...) } matchCount := len(match) / 2 argumentList := make([]Value, matchCount+2) for index := 0; index < matchCount; index++ { offset := 2 * index if match[offset] != -1 { argumentList[index] = toValue_string(target[match[offset]:match[offset+1]]) } else { argumentList[index] = UndefinedValue() } } argumentList[matchCount+0] = toValue_int(match[0]) argumentList[matchCount+1] = toValue_string(target) replacement := toString(replace.Call(UndefinedValue(), argumentList)) result = append(result, []byte(replacement)...) lastIndex = match[1] } } else { replace := []byte(toString(replaceValue)) for _, match := range found { result = builtinString_findAndReplaceString(result, lastIndex, match, target, replace) lastIndex = match[1] } } if lastIndex != len(target) { result = append(result, target[lastIndex:]...) } if global && searchObject != nil { searchObject.put("lastIndex", toValue_int(lastIndex), true) } return toValue_string(string(result)) } return UndefinedValue() }