public static object BlockReplaceAll(ConversionStorage<MutableString>/*!*/ tosConversion, RubyScope/*!*/ scope, [NotNull]BlockParam/*!*/ block, MutableString/*!*/ self, [NotNull]RubyRegex pattern) { object blockResult; MutableString result; self.TrackChanges(); object r = BlockReplaceAll(tosConversion, scope, self, block, pattern, out blockResult, out result) ? blockResult : (result ?? self.Clone()); RequireNoVersionChange(self); return r; }
private static object BlockReplaceInPlace(ConversionStorage<MutableString>/*!*/ tosConversion, RubyScope/*!*/ scope, BlockParam/*!*/ block, MutableString/*!*/ self, RubyRegex/*!*/ pattern, bool replaceAll) { object blockResult; 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); 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); }
public static object BlockReplaceAll(ConversionStorage<MutableString>/*!*/ tosConversion, RubyScope/*!*/ scope, [NotNull]BlockParam/*!*/ block, MutableString/*!*/ self, [NotNull]MutableString matchString) { object blockResult; MutableString result; // TODO: var regex = new RubyRegex(MutableString.CreateMutable(Regex.Escape(matchString.ToString()), matchString.Encoding), RubyRegexOptions.NONE); self.TrackChanges(); object r = BlockReplaceAll(tosConversion, scope, self, block, regex, out blockResult, out result) ? blockResult : (result ?? self.Clone()); RequireNoVersionChange(self); return r; }
// 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 object EachLine(BlockParam block, MutableString/*!*/ self, [DefaultProtocol]MutableString separator, int start) { self.TrackChanges(); MutableString paragraphSeparator; if (separator == null || separator.IsEmpty) { separator = DefaultLineSeparator; paragraphSeparator = DefaultParagraphSeparator; } else { paragraphSeparator = null; } // TODO: this is slow, refactor when we redo MutableString MutableString str = self; // In "normal" mode just split the string at the end of each seperator occurrance. // In "paragraph" mode, split the string at the end of each occurrance of two or more // successive seperators. while (start < self.Length) { int end; if (paragraphSeparator == null) { end = str.IndexOf(separator, start); if (end >= 0) { end += separator.Length; } else { end = str.Length; } } else { end = str.IndexOf(paragraphSeparator, start); if (end >= 0) { end += (2 * separator.Length); while (str.IndexOf(separator, end) == end) { end += separator.Length; } } else { end = str.Length; } } // Yield the current line if (block == null) { throw RubyExceptions.NoBlockGiven(); } object result; MutableString line = self.CreateInstance().TaintBy(self).Append(str, start, end - start); if (block.Yield(line, out result)) { return result; } start = end; } // MRI 1.8: this is checked after each line // MRI 1.9: not checked at all // Ensure that the underlying string has not been mutated during the iteration RequireNoVersionChange(self); return self; }