public bool MatchString(Runtime runtime, string str, int pos, bool allow_zero, ref RxResult oldState) { int st = pos >= 0 ? pos : 0; for (int i = st; i <= str.Length; ++i) { var match = regex.Match(str, i); if (match.Success) { RxResult res; if (pos >= 0 && pos == match.Index + match.Length && !allow_zero) { res.Matched = false; continue; } res.Matched = match.Success; res.Start = match.Index; res.End = match.Index + match.Length; if (match.Groups.Count > 1) { res.Captures = new RxCapture[match.Groups.Count - 1]; res.StringCaptures = new string[match.Groups.Count - 1]; for (int j = 0; j < res.Captures.Length; ++j) { var capt = match.Groups[j + 1]; if (capt.Success) { res.Captures[j].Start = capt.Index; res.Captures[j].End = capt.Index + capt.Length; res.StringCaptures[j] = str.Substring(capt.Index, capt.Length); } else { res.Captures[j].Start = -1; res.Captures[j].End = -1; res.StringCaptures[j] = null; } } } else { res.Captures = null; res.StringCaptures = null; } oldState = runtime.LastMatch; runtime.LastMatch = res; return res.Matched; } } return false; }
public IP5Any MatchGlobal(Runtime runtime, IP5Any value, int flags, Opcode.ContextValues cxt, ref RxResult oldState) { return P5Regex.MatchGlobalHelper(this, runtime, value, flags, cxt, ref oldState); }
private bool MatchAt(Runtime runtime, string str, int pos, out RxResult res) { int len = str.Length; res.Matched = false; res.Start = res.End = -1; res.Captures = null; res.StringCaptures = null; RxContext cxt; cxt.Pos = pos; cxt.Groups = new List<RxGroup>(); cxt.States = new List<RxState>(); cxt.StateBacktrack = new List<int>(); if (Captures > 0) cxt.Captures = new RxCapture[Captures]; else cxt.Captures = null; if (Saved > 0) cxt.Saved = new int[Saved]; else cxt.Saved = null; cxt.LastOpenCapture = cxt.LastClosedCapture = -1; for (int index = 0; index >= 0;) { switch (Ops[index].Number) { case Opcode.OpNumber.OP_RX_START_MATCH: // do nothing for now ++index; break; case Opcode.OpNumber.OP_RX_EXACT: case Opcode.OpNumber.OP_RX_EXACT_I: { var s = Exact[Ops[index].Index]; bool case_insensitive = Ops[index].Number == Opcode.OpNumber.OP_RX_EXACT_I; if ( cxt.Pos + s.Length > len || string.Compare(str, cxt.Pos, s, 0, s.Length, case_insensitive) != 0) index = Backtrack(ref cxt); else { cxt.Pos += s.Length; ++index; } break; } case Opcode.OpNumber.OP_RX_SAVE_POS: { cxt.Saved[Ops[index].Index] = cxt.Pos; ++index; break; } case Opcode.OpNumber.OP_RX_RESTORE_POS: { cxt.Pos = cxt.Saved[Ops[index].Index]; ++index; break; } case Opcode.OpNumber.OP_RX_ANY_NONEWLINE: { if (cxt.Pos == len || str[cxt.Pos] == '\n') index = Backtrack(ref cxt); else { ++cxt.Pos; ++index; } break; } case Opcode.OpNumber.OP_RX_ANY: { if (cxt.Pos == len) index = Backtrack(ref cxt); else { ++cxt.Pos; ++index; } break; } case Opcode.OpNumber.OP_RX_CLASS: { var c = Classes[Ops[index].Index]; if (cxt.Pos < len) { char ch = str[cxt.Pos]; ++cxt.Pos; ++index; if (c.Exact.IndexOf(ch) >= 0) break; if ((c.Flags & Opcode.RX_CLASS_WORDS) != 0 && IsWord(ch)) break; if ((c.Flags & Opcode.RX_CLASS_NOT_WORDS) != 0 && !IsWord(ch)) break; if ((c.Flags & Opcode.RX_CLASS_DIGITS) != 0 && char.IsDigit(ch)) break; if ((c.Flags & Opcode.RX_CLASS_NOT_DIGITS) != 0 && !char.IsDigit(ch)) break; if ((c.Flags & Opcode.RX_CLASS_SPACES) != 0 && char.IsWhiteSpace(ch)) break; if ((c.Flags & Opcode.RX_CLASS_NOT_SPACES) != 0 && !char.IsWhiteSpace(ch)) break; } index = Backtrack(ref cxt); break; } case Opcode.OpNumber.OP_RX_BEGINNING: { if (cxt.Pos != 0) index = Backtrack(ref cxt); else ++index; break; } case Opcode.OpNumber.OP_RX_START_GROUP: { var grp = new RxGroup(-1); cxt.Groups.Add(grp); cxt.StateBacktrack.Add(cxt.States.Count); index = Targets[Ops[index].Index]; break; } case Opcode.OpNumber.OP_RX_BACKTRACK: case Opcode.OpNumber.OP_RX_TRY: { var st = new RxState(cxt.Pos, Targets[Ops[index].Index], cxt.Groups.Count); cxt.States.Add(st); ++index; break; } case Opcode.OpNumber.OP_RX_POP_STATE: { cxt.States.RemoveAt(cxt.States.Count - 1); ++index; break; } case Opcode.OpNumber.OP_RX_FAIL: { index = Backtrack(ref cxt); break; } case Opcode.OpNumber.OP_RX_QUANTIFIER: { var group = cxt.Groups[cxt.Groups.Count - 1]; var quant = Quantifiers[Ops[index].Index]; int lastMatch = group.LastMatch; ++index; group.Count += 1; group.LastMatch = cxt.Pos; if (group.Count > 0 && quant.Group >= 0) EndCapture(ref cxt, quant.Group); // max repeat count if (group.Count == quant.MaxCount) { cxt.Groups.RemoveAt(cxt.Groups.Count - 1); break; } // zero-length match if (cxt.Pos == lastMatch) { break; } RxSavedGroups gr; if (group.Count == 0 || group.Count >= quant.MinCount) SaveGroups(ref cxt, quant.SubgroupStart, quant.SubgroupEnd, group.Count == 0, out gr); else gr = new RxSavedGroups(); if (group.Count == 0 && quant.MinCount > 0) { // force failure on backtrack var st = new RxState(cxt.Pos, -1, -1); st.Groups = gr; cxt.States.Add(st); } else if (quant.IsGreedy && group.Count >= quant.MinCount) { var st = new RxState(cxt.Pos, index, cxt.Groups.Count - 1); st.Groups = gr; cxt.States.Add(st); } cxt.Groups[cxt.Groups.Count - 1] = group; // if nongreedy, match at least min if (!quant.IsGreedy && group.Count >= quant.MinCount) { var st = new RxState(cxt.Pos, Targets[quant.To], cxt.Groups.Count); st.Groups = gr; cxt.States.Add(st); break; } if (quant.Group >= 0) StartCapture(ref cxt, quant.Group); index = Targets[quant.To]; break; } case Opcode.OpNumber.OP_RX_CAPTURE_START: { StartCapture(ref cxt, Ops[index].Index); ++index; break; } case Opcode.OpNumber.OP_RX_CAPTURE_END: { EndCapture(ref cxt, Ops[index].Index); ++index; break; } case Opcode.OpNumber.OP_RX_ACCEPT: { for (int i = cxt.LastOpenCapture + 1; i < Ops[index].Index; ++i) cxt.Captures[i].Start = cxt.Captures[i].End = -1; if (cxt.Captures != null) { res.StringCaptures = new string[cxt.Captures.Length]; for (int i = 0; i < cxt.Captures.Length; ++i) if (cxt.Captures[i].End != -1) res.StringCaptures[i] = str.Substring(cxt.Captures[i].Start, cxt.Captures[i].End - cxt.Captures[i].Start); } res.Start = pos; res.End = cxt.Pos; res.Captures = cxt.Captures; res.Matched = true; index = -1; break; } case Opcode.OpNumber.OP_JUMP: index = Targets[Ops[index].Index]; break; default: throw new System.Exception("PANIC: unhandled opcode " + Ops[index].Number); } } return res.Matched; }
public bool MatchString(Runtime runtime, string str, int pos, bool allow_zero, ref RxResult oldState) { int st = pos >= 0 ? pos : 0; for (int i = st; i <= str.Length; ++i) { RxResult res; MatchAt(runtime, str, i, out res); if (res.Matched) { if (pos >= 0 && pos == res.End && !allow_zero) { res.Matched = false; continue; } oldState = runtime.LastMatch; runtime.LastMatch = res; return true; } } return false; }
public static IP5Any MatchHelper(IP5Regex regex, Runtime runtime, IP5Any value, int flags, Opcode.ContextValues cxt, ref RxResult oldState) { bool match = regex.MatchString(runtime, value.AsString(runtime), -1, false, ref oldState); if (cxt != Opcode.ContextValues.LIST) { return new P5Scalar(runtime, match); } else if (match && runtime.LastMatch.StringCaptures.Length > 0) { var res = new IP5Any[runtime.LastMatch.StringCaptures.Length]; for (int i = 0; i < runtime.LastMatch.StringCaptures.Length; ++i) res[i] = new P5Scalar(runtime, runtime.LastMatch.StringCaptures[i]); return new P5List(runtime, res); } else { return new P5List(runtime, match); } }
public static IP5Any MatchGlobalHelper(IP5Regex regex, Runtime runtime, IP5Any value, int flags, Opcode.ContextValues cxt, ref RxResult oldState) { var scalar = value as P5Scalar; bool pos_set; int pos = value.GetPos(runtime, out pos_set); string str = value.AsString(runtime); bool match; IP5Any result; if (cxt != Opcode.ContextValues.LIST) { match = regex.MatchString(runtime, str, pos, pos_set, ref oldState); result = new P5Scalar(runtime, match); if (scalar != null) { if (match) scalar.SetPos(runtime, runtime.LastMatch.End, false); else if ((flags & Opcode.RX_KEEP) == 0) scalar.UnsetPos(runtime); } } else { var capt = new List<IP5Any>(); for (;;) { match = regex.MatchString(runtime, str, pos, pos_set, ref oldState); if (match) { if (runtime.LastMatch.StringCaptures != null) { foreach (var s in runtime.LastMatch.StringCaptures) capt.Add(new P5Scalar(runtime, s)); } else { string s = str.Substring(runtime.LastMatch.Start, runtime.LastMatch.End - runtime.LastMatch.Start); capt.Add(new P5Scalar(runtime, s)); } } else break; pos = runtime.LastMatch.End; } if (scalar != null) { if ((flags & Opcode.RX_KEEP) != 0) scalar.SetPos(runtime, pos, false); else scalar.UnsetPos(runtime); } result = new P5List(runtime, capt); } return result; }