/// <summary> /// Yields each of the possible matches of the regex from this point onwards as a CharSetString. /// </summary> /// <param name="charIdx"> /// The current index of the match in the string /// </param> /// <param name="currentConstraints"> /// The prior constraints on any matches /// </param> public override IEnumerable<CharSetString> GeneratePossibleMatches(int charIdx, CharSetString currentConstraints) { if (CurrentMatch != null) { throw new InvalidOperationException("There is already a match in progress"); } foreach (var choice in Choices) { var first = choice.First(); foreach (var choiceMatchGen in first.GeneratePossibleMatches(charIdx, currentConstraints)) { // choiceMatch may be modified later on (see RegexBackReference), so we promote it // to a RevertibleCharSetString var choiceMatch = new RevertibleCharSetString(choiceMatchGen); CurrentMatch = choiceMatch; foreach (var remainderMatch in Next.GeneratePossibleMatches( charIdx + choiceMatch.Length, currentConstraints)) { yield return choiceMatch.Concat(remainderMatch); } CurrentMatch = null; } } }
public IEnumerable<CharSetString> GeneratePossibleMatches(int charIdx, CharSetString currentConstraints) { if (charIdx == currentConstraints.Length) { yield return CharSetString.EmptyString(); } }
public override IEnumerable<CharSetString> GeneratePossibleMatches(int charIdx, CharSetString currentConstraints) { // Is the groupMatch applicable here? // // The constraints here retrospectively modify the earlier match -- any matching string // must match both here and before, i.e. // a regex like "(.)\1" applied to ".A" must become "AA" // // We bookmark the previous match, so that we can put things back how we found them // after iterating over this possible path. var previousGroupMatch = Group.CurrentMatch; previousGroupMatch.Bookmark(); var i = 0; foreach (var groupMatchChar in previousGroupMatch) { if (charIdx + i >= currentConstraints.Length) { goto noMatch; } try { groupMatchChar.Intersect(currentConstraints[charIdx + i]); } catch (CharSet.EmptyIntersectionException) { goto noMatch; } i++; } foreach (var remainderMatch in Next.GeneratePossibleMatches( charIdx + previousGroupMatch.Length, currentConstraints)) { // The value returned here is valid only briefly: we will reuse the // same strings in the next element. // See comments on RegexNonTerminalAtom.GeneratePossibleMatches yield return previousGroupMatch.Concat(remainderMatch); } noMatch: previousGroupMatch.RevertToBookmark(); }
/// <summary> /// Yields each of the possible matches of the regex from this point onwards as a CharSetString. /// </summary> /// <param name="charIdx"> /// The current index of the match in the string /// </param> /// <param name="currentConstraints"> /// The prior constraints on any matches /// </param> public override IEnumerable<CharSetString> GeneratePossibleMatches(int charIdx, CharSetString currentConstraints) { if (MinReps == 0) { foreach (var nextMatch in Next.GeneratePossibleMatches(charIdx, currentConstraints)) { yield return nextMatch; } } Inner.Next = new RegexEmptyMatchTerminalAtom(); var currentInnerMatches = new List<CharSetString> { CharSetString.EmptyString() }; for (int innerMatchCount = 1; innerMatchCount <= (MaxReps ?? Int32.MaxValue); innerMatchCount++) { var newInnerMatches = new List<CharSetString>(); foreach (var currentInnerMatch in currentInnerMatches) { // TODO: could group the currentInnerMatches by length here, to save re-computing // the following repeatedly for the same arguments in some cases foreach (var nextInnerMatch in Inner.GeneratePossibleMatches( charIdx + currentInnerMatch.Length, currentConstraints)) { var newInnerMatch = currentInnerMatch.Concat(nextInnerMatch); newInnerMatches.Add(newInnerMatch); if (innerMatchCount >= MinReps) { foreach (var nextMatch in Next.GeneratePossibleMatches( charIdx + newInnerMatch.Length, currentConstraints)) { yield return newInnerMatch.Concat(nextMatch); } } } } currentInnerMatches = newInnerMatches; if (!currentInnerMatches.Any()) { break; } } }
/// <summary> /// Yields each of the possible matches of the regex from this point onwards as a CharSetString. /// </summary> /// <param name="charIdx"> /// The current index of the match in the string /// </param> /// <param name="currentConstraints"> /// The prior constraints on any matches /// </param> public override IEnumerable<CharSetString> GeneratePossibleMatches(int charIdx, CharSetString currentConstraints) { if (charIdx >= currentConstraints.Length) { yield break; // no match } var thisCharSet = currentConstraints[charIdx].Clone(); try { thisCharSet.Intersect(CharSet); } catch (CharSet.EmptyIntersectionException) { yield break; // no match } foreach (var remainderMatch in Next.GeneratePossibleMatches(charIdx + 1, currentConstraints)) { yield return CharSetString.Cons(thisCharSet, remainderMatch); } }
/// <param name="clues"> /// The clues as a 3xN grid /// </param> public HexRegexCrossword(Regex[,] clues) { if (3 != clues.GetUpperBound(0) + 1 || 0 != clues.GetLowerBound(0) || 0 != clues.GetLowerBound(1)) { throw new ArgumentException("The clue array must be 3 X rowCount"); } Clues = clues; RowCount = clues.GetUpperBound(1) + 1; SideLength = (RowCount + 1)/2; GridRows = new CharSetString[3, RowCount]; // Build up a grid of cells by Q/R. // The max coord will be < +/- sideLength // Since coords may be negative, this array is offset by +sideLength _cellsByQROffsetBySideLength = new CharSet[2 * SideLength, 2 * SideLength]; for (int axis = 0; axis < 3; axis++) { for (int idx = -(SideLength - 1); idx <= (SideLength - 1); idx++) { var row = new List<CharSet>(); for (int offset = 0;; offset++) { var qr = AxisIdxOffsetToQR(axis, idx, offset); var cell = GetCellByQR(qr); if (cell == null) // qr is out of range { break; } row.Add(cell); } GridRows[axis, idx + (SideLength - 1)] = new CharSetString(row); } } }
/// <summary> /// Enumerates the possible matches for this regex component at the given starting index and /// under the given constraints. /// /// Careful: the returned CharSetStrings are only valid when they are first returned from the /// iterator. Parts of the string are shared between successive return values. You must copy /// or consume the output while the iteration is proceeding. /// /// See RegexBackReference for more on this. /// </summary> /// <param name="charIdx"></param> /// <param name="currentConstraints"></param> /// <returns></returns> public abstract IEnumerable<CharSetString> GeneratePossibleMatches(int charIdx, CharSetString currentConstraints);
/// <summary> /// Given a string of possible characters, attempts to constrain the possibilities /// to only strings which match this regex. /// /// Returns true if any changes were made. /// </summary> public bool AddConstraints(CharSetString currentConstraints) { var first = Atoms.First(); var possibilitiesSeen = CharSetString.EmptySetsStringOfLength(currentConstraints.Length); foreach (var possibility in first.GeneratePossibleMatches(0, currentConstraints)) { possibilitiesSeen.Union(possibility); } return currentConstraints.Intersect(possibilitiesSeen); }
public IEnumerable<CharSetString> GeneratePossibleMatches(int charIdx, CharSetString currentConstraints) { return new[] { CharSetString.EmptyString() }; }