public static MutableString/*!*/ Replace(MutableString/*!*/ self, [DefaultProtocol, NotNull]MutableString/*!*/ other) { // Handle case where objects are the same identity if (ReferenceEquals(self, other)) { return self; } self.Clear(); self.Append(other); return self.TaintBy(other); }
public static MutableString/*!*/ ReplaceSubstring(MutableString/*!*/ self, [DefaultProtocol]int start, [DefaultProtocol]int charsToOverwrite, [DefaultProtocol, NotNull]MutableString/*!*/ value) { if (charsToOverwrite < 0) { throw RubyExceptions.CreateIndexError(String.Format("negative length {0}", charsToOverwrite)); } if (System.Math.Abs(start) > self.Length) { throw RubyExceptions.CreateIndexError(String.Format("index {0} out of string", start)); } start = start < 0 ? start + self.Length : start; if (charsToOverwrite <= value.Length) { int insertIndex = start + charsToOverwrite; int limit = charsToOverwrite; if (insertIndex > self.Length) { limit -= insertIndex - self.Length; insertIndex = self.Length; } self.Replace(start, limit, value); } else { self.Replace(start, value.Length, value); int pos = start + value.Length; int charsToRemove = charsToOverwrite - value.Length; int charsLeftInString = self.Length - pos; self.Remove(pos, System.Math.Min(charsToRemove, charsLeftInString)); } self.TaintBy(value); return value; }
private static object BlockReplaceInPlace(RubyScope/*!*/ scope, BlockParam/*!*/ block, MutableString/*!*/ self, RubyRegex/*!*/ pattern, bool replaceAll) { object blockResult; uint version = self.Version; // prepare replacement in a builder: MutableString builder; if (replaceAll ? BlockReplaceAll(scope, self, block, pattern, out blockResult, out builder) : BlockReplaceFirst(scope, self, block, pattern, out blockResult, out builder)) { // block jumped: return blockResult; } // unsuccessful match: if (builder == null) { return null; } RequireNoVersionChange(version, self); if (self.IsFrozen) { throw new RuntimeError("string frozen"); } // replace content of self with content of the builder: self.Replace(0, self.Length, builder); return self.TaintBy(builder); }
private static MutableString ReplaceInPlace(RubyScope/*!*/ scope, MutableString/*!*/ self, RubyRegex/*!*/ pattern, MutableString/*!*/ replacement, bool replaceAll) { MutableString builder = replaceAll ? ReplaceAll(scope, self, replacement, pattern) : ReplaceFirst(scope, self, replacement, pattern); // unsuccessful match: if (builder == null) { return null; } self.Replace(0, self.Length, builder); return self.TaintBy(builder); }
// returns true if block jumped // "result" will be null if there is no successful match private static bool BlockReplaceFirst(RubyScope/*!*/ scope, MutableString/*!*/ input, BlockParam/*!*/ block, RubyRegex/*!*/ pattern, out object blockResult, out MutableString result) { var matchScope = scope.GetInnerMostClosureScope(); MatchData match = RegexpOps.Match(scope, pattern, input); if (match == null || !match.Success) { result = null; blockResult = null; matchScope.CurrentMatch = null; return false; } // copy upfront so that no modifications to the input string are included in the result: result = input.Clone(); matchScope.CurrentMatch = match; if (block.Yield(MutableString.Create(match.Value), out blockResult)) { return true; } // resets the $~ scope variable to the last match (skipd if block jumped): matchScope.CurrentMatch = match; MutableString replacement = Protocols.ConvertToString(scope.RubyContext, blockResult); result.TaintBy(replacement); // Note - we don't interpolate special sequences like \1 in block return value result.Replace(match.Index, match.Length, replacement); blockResult = null; return false; }
// returns true if block jumped // "result" will be null if there is no successful match private static bool BlockReplaceAll(RubyScope/*!*/ scope, MutableString/*!*/ input, BlockParam/*!*/ block, RubyRegex/*!*/ regex, out object blockResult, out MutableString result) { var matchScope = scope.GetInnerMostClosureScope(); MatchCollection matches = regex.Matches(input); if (matches.Count == 0) { result = null; blockResult = null; matchScope.CurrentMatch = null; return false; } // create an empty result: result = input.CreateInstance().TaintBy(input); int offset = 0; foreach (Match match in matches) { MatchData currentMatch = new MatchData(match, input); matchScope.CurrentMatch = currentMatch; uint version = input.Version; if (block.Yield(MutableString.Create(match.Value), out blockResult)) { return true; } if (input.Version != version) { return false; } // resets the $~ scope variable to the last match (skipd if block jumped): matchScope.CurrentMatch = currentMatch; MutableString replacement = Protocols.ConvertToString(scope.RubyContext, blockResult); result.TaintBy(replacement); // prematch: result.Append(input, offset, match.Index - offset); // replacement (unlike ReplaceAll, don't interpolate special sequences like \1 in block return value): result.Append(replacement); offset = match.Index + match.Length; } // post-last-match: result.Append(input, offset, input.Length - offset); blockResult = null; return false; }
// returns true if block jumped // "result" will be null if there is no successful match private static bool BlockReplaceAll(ConversionStorage<MutableString>/*!*/ tosConversion, RubyScope/*!*/ scope, MutableString/*!*/ input, BlockParam/*!*/ block, RubyRegex/*!*/ regex, out object blockResult, out MutableString result) { var matchScope = scope.GetInnerMostClosureScope(); var matches = regex.Matches(tosConversion.Context.KCode, input); if (matches.Count == 0) { result = null; blockResult = null; matchScope.CurrentMatch = null; return false; } // create an empty result: result = input.CreateInstance().TaintBy(input); int offset = 0; foreach (MatchData match in matches) { matchScope.CurrentMatch = match; input.TrackChanges(); if (block.Yield(match.GetValue(), out blockResult)) { return true; } if (input.HasChanged) { return false; } // resets the $~ scope variable to the last match (skipd if block jumped): matchScope.CurrentMatch = match; MutableString replacement = Protocols.ConvertToString(tosConversion, blockResult); result.TaintBy(replacement); // prematch: result.Append(input, offset, match.Index - offset); // replacement (unlike ReplaceAll, don't interpolate special sequences like \1 in block return value): result.Append(replacement); offset = match.Index + match.Length; } // post-last-match: result.Append(input, offset, input.Length - offset); blockResult = null; return false; }
public static MutableString/*!*/ Reinitialize(MutableString/*!*/ self, [DefaultProtocol, NotNull]MutableString other) { if (ReferenceEquals(self, other)) { return self; } self.Clear(); self.Append(other); return self.TaintBy(other); }
private static MutableString ReplaceInPlace(ConversionStorage<MutableString> toS, BinaryOpStorage hashDefault, RubyScope/*!*/ scope, MutableString/*!*/ self, RubyRegex/*!*/ pattern, Union<IDictionary<object, object>, MutableString>/*!*/ replacement, bool replaceAll) { self.RequireNotFrozen(); MutableString builder = replaceAll ? ReplaceAll(toS, hashDefault, scope, self, replacement, pattern) : ReplaceFirst(toS, hashDefault, scope, self, replacement, pattern); // unsuccessful match: if (builder == null) { return null; } self.Replace(0, self.Length, builder); return self.TaintBy(builder); }
private static object BlockReplaceInPlace(ConversionStorage<MutableString>/*!*/ tosConversion, RubyScope/*!*/ scope, BlockParam/*!*/ block, MutableString/*!*/ self, RubyRegex/*!*/ pattern, bool replaceAll) { object blockResult; self.RequireNotFrozen(); self.TrackChanges(); // prepare replacement in a builder: MutableString builder; if (replaceAll ? BlockReplaceAll(tosConversion, scope, self, block, pattern, out blockResult, out builder) : BlockReplaceFirst(tosConversion, scope, self, block, pattern, out blockResult, out builder)) { // block jumped: return blockResult; } // unsuccessful match: if (builder == null) { return null; } RequireNoVersionChange(self); // replace content of self with content of the builder: self.Replace(0, self.Length, builder); return self.TaintBy(builder); }
private static void AppendReplacementExpression(MutableString/*!*/ input, MatchData/*!*/ match, MutableString/*!*/ result, MutableString/*!*/ replacement) { int backslashCount = 0; for (int i = 0; i < replacement.Length; i++) { char c = replacement.GetChar(i); if (c == '\\') { backslashCount++; } else if (backslashCount == 0) { result.Append(c); } else { AppendBackslashes(backslashCount, result, 0); // Odd number of \'s + digit means insert replacement expression if ((backslashCount & 1) == 1) { if (Char.IsDigit(c)) { AppendGroupByIndex(match, c - '0', result); } else if (c == '&') { AppendGroupByIndex(match, match.GroupCount - 1, result); } else if (c == '`') { // Replace with everything in the input string BEFORE the match result.Append(input, 0, match.Index); } else if (c == '\'') { // Replace with everything in the input string AFTER the match int start = match.Index + match.Length; // TODO: result.Append(input, start, input.GetLength() - start); } else if (c == '+') { // Replace last character in last successful match group AppendLastCharOfLastMatchGroup(match, result); } else { // unknown escaped replacement char, go ahead and replace untouched result.Append('\\'); result.Append(c); } } else { // Any other # of \'s or a non-digit character means insert literal \'s and character AppendBackslashes(backslashCount, result, 1); result.Append(c); } backslashCount = 0; } } AppendBackslashes(backslashCount, result, 1); result.TaintBy(replacement); }