[Serializable]
public partial class Regex : ISerializable {
-#if NET_2_0
- private static int cache_size = 15;
-#endif
-#if !TARGET_JVM
+#if !TARGET_JVM && !FULL_AOT_RUNTIME
[MonoTODO]
public static void CompileToAssembly (RegexCompilationInfo [] regexes, AssemblyName aname)
{
public static string Escape (string str)
{
+ if (str == null)
+ throw new ArgumentNullException ("str");
return Parser.Escape (str);
}
public static string Unescape (string str)
{
+ if (str == null)
+ throw new ArgumentNullException ("str");
return Parser.Unescape (str);
}
return re.Split (input);
}
-#if NET_2_0
- [MonoTODO ("should be used somewhere ? FactoryCache ?")]
+ static FactoryCache cache = new FactoryCache (15);
public static int CacheSize {
- get { return cache_size; }
+ get { return cache.Capacity; }
set {
if (value < 0)
throw new ArgumentOutOfRangeException ("CacheSize");
- cache_size = value;
+
+ cache.Capacity = value;
}
}
-#endif
// private
- private static FactoryCache cache = new FactoryCache (200); // TODO put some meaningful number here
// constructors
public Regex (string pattern, RegexOptions options)
{
+ if (pattern == null)
+ throw new ArgumentNullException ("pattern");
+ validate_options (options);
this.pattern = pattern;
this.roptions = options;
Init ();
}
+
+ static void validate_options (RegexOptions options)
+ {
+ const RegexOptions allopts =
+ RegexOptions.None |
+ RegexOptions.IgnoreCase |
+ RegexOptions.Multiline |
+ RegexOptions.ExplicitCapture |
+#if MOBILE || !NET_2_1
+ RegexOptions.Compiled |
+#endif
+ RegexOptions.Singleline |
+ RegexOptions.IgnorePatternWhitespace |
+ RegexOptions.RightToLeft |
+ RegexOptions.ECMAScript |
+ RegexOptions.CultureInvariant;
+
+ const RegexOptions ecmaopts =
+ RegexOptions.IgnoreCase |
+ RegexOptions.Multiline |
+#if MOBILE || !NET_2_1
+ RegexOptions.Compiled |
+#endif
+ RegexOptions.ECMAScript;
+
+ if ((options & ~allopts) != 0)
+ throw new ArgumentOutOfRangeException ("options");
+ if ((options & RegexOptions.ECMAScript) != 0 && (options & ~ecmaopts) != 0)
+ throw new ArgumentOutOfRangeException ("options");
+ }
+
#if !TARGET_JVM
private void Init ()
{
InitNewRegex();
} else {
this.group_count = this.machineFactory.GroupCount;
+ this.gap = this.machineFactory.Gap;
this.mapping = this.machineFactory.Mapping;
- this._groupNumberToNameMap = this.machineFactory.NamesMapping;
+ this.group_names = this.machineFactory.NamesMapping;
}
}
#endif
private void InitNewRegex ()
{
this.machineFactory = CreateMachineFactory (this.pattern, this.roptions);
+ cache.Add (this.pattern, this.roptions, this.machineFactory);
this.group_count = machineFactory.GroupCount;
+ this.gap = this.machineFactory.Gap;
this.mapping = machineFactory.Mapping;
- this._groupNumberToNameMap = this.machineFactory.NamesMapping;
+ this.group_names = this.machineFactory.NamesMapping;
}
- static readonly bool old_rx = Environment.GetEnvironmentVariable ("MONO_OLD_RX") != null;
+#if !NET_2_1
+ // The new rx engine seems to be working now, but
+ // potential problems are being tracked down here:
+ // https://bugzilla.novell.com/show_bug.cgi?id=470827
+ static readonly bool old_rx =
+ Environment.GetEnvironmentVariable ("MONO_NEW_RX") == null;
+#endif
private static IMachineFactory CreateMachineFactory (string pattern, RegexOptions options)
{
Parser psr = new Parser ();
RegularExpression re = psr.ParseRegularExpression (pattern, options);
+#if NET_2_1
+ ICompiler cmp = new PatternCompiler ();
+#else
ICompiler cmp;
if (!old_rx) {
if ((options & RegexOptions.Compiled) != 0)
} else {
cmp = new PatternCompiler ();
}
+#endif
re.Compile (cmp, (options & RegexOptions.RightToLeft) != 0);
IMachineFactory machineFactory = cmp.GetMachineFactory ();
- machineFactory.Mapping = psr.GetMapping ();
+ Hashtable mapping = new Hashtable ();
+ machineFactory.Gap = psr.GetMapping (mapping);
+ machineFactory.Mapping = mapping;
machineFactory.NamesMapping = GetGroupNamesArray (machineFactory.GroupCount, machineFactory.Mapping);
return machineFactory;
}
-#if NET_2_0
- protected
-#else
- private
-#endif
- Regex (SerializationInfo info, StreamingContext context) :
+ protected Regex (SerializationInfo info, StreamingContext context) :
this (info.GetString ("pattern"),
(RegexOptions) info.GetValue ("options", typeof (RegexOptions)))
{
}
-#if ONLY_1_1 && !TARGET_JVM
- // fixes public API signature
- ~Regex ()
- {
- }
-#endif
// public instance properties
public RegexOptions Options {
public string [] GetGroupNames ()
{
- string [] names = new string [mapping.Count];
- mapping.Keys.CopyTo (names, 0);
-
+ string [] names = new string [1 + group_count];
+ Array.Copy (group_names, names, 1 + group_count);
return names;
}
- public int[] GetGroupNumbers ()
+ public int [] GetGroupNumbers ()
{
- int[] numbers = new int [mapping.Count];
- mapping.Values.CopyTo (numbers, 0);
-
+ int [] numbers = new int [1 + group_count];
+ Array.Copy (GroupNumbers, numbers, 1 + group_count);
return numbers;
}
public string GroupNameFromNumber (int i)
{
- if (i < 0 || i > group_count)
+ i = GetGroupIndex (i);
+ if (i < 0)
return "";
- return _groupNumberToNameMap [i];
+ return group_names [i];
}
public int GroupNumberFromName (string name)
{
- if (mapping.Contains (name))
- return (int) mapping [name];
+ if (!mapping.Contains (name))
+ return -1;
+ int i = (int) mapping [name];
+ if (i >= gap)
+ i = Int32.Parse (name);
+ return i;
+ }
+
+ internal int GetGroupIndex (int number)
+ {
+ if (number < gap)
+ return number;
+ if (gap > group_count)
+ return -1;
+ return Array.BinarySearch (GroupNumbers, gap, group_count - gap + 1, number);
+ }
- return -1;
+ int default_startat (string input)
+ {
+ return (RightToLeft && input != null) ? input.Length : 0;
}
// match methods
public bool IsMatch (string input)
{
- return IsMatch (input, RightToLeft ? input.Length : 0);
+ return IsMatch (input, default_startat (input));
}
public bool IsMatch (string input, int startat)
public Match Match (string input)
{
- return Match (input, RightToLeft ? input.Length : 0);
+ return Match (input, default_startat (input));
}
public Match Match (string input, int startat)
{
+ if (input == null)
+ throw new ArgumentNullException ("input");
+ if (startat < 0 || startat > input.Length)
+ throw new ArgumentOutOfRangeException ("startat");
return CreateMachine ().Scan (this, input, startat, input.Length);
}
- public Match Match (string input, int startat, int length)
+ public Match Match (string input, int beginning, int length)
{
- return CreateMachine ().Scan (this, input, startat, startat + length);
+ if (input == null)
+ throw new ArgumentNullException ("input");
+ if (beginning < 0 || beginning > input.Length)
+ throw new ArgumentOutOfRangeException ("beginning");
+ if (length < 0 || length > input.Length - beginning)
+ throw new ArgumentOutOfRangeException ("length");
+ return CreateMachine ().Scan (this, input, beginning, beginning + length);
}
public MatchCollection Matches (string input)
{
- return Matches (input, RightToLeft ? input.Length : 0);
+ return Matches (input, default_startat (input));
}
public MatchCollection Matches (string input, int startat)
public string Replace (string input, MatchEvaluator evaluator)
{
- return Replace (input, evaluator, Int32.MaxValue, RightToLeft ? input.Length : 0);
+ return Replace (input, evaluator, Int32.MaxValue, default_startat (input));
}
public string Replace (string input, MatchEvaluator evaluator, int count)
{
- return Replace (input, evaluator, count, RightToLeft ? input.Length : 0);
+ return Replace (input, evaluator, count, default_startat (input));
}
class Adapter {
public string Replace (string input, MatchEvaluator evaluator, int count, int startat)
{
+ if (input == null)
+ throw new ArgumentNullException ("input");
+ if (evaluator == null)
+ throw new ArgumentNullException ("evaluator");
+ if (count < -1)
+ throw new ArgumentOutOfRangeException ("count");
+ if (startat < 0 || startat > input.Length)
+ throw new ArgumentOutOfRangeException ("startat");
+
BaseMachine m = (BaseMachine)CreateMachine ();
if (RightToLeft)
public string Replace (string input, string replacement)
{
- return Replace (input, replacement, Int32.MaxValue, RightToLeft ? input.Length : 0);
+ return Replace (input, replacement, Int32.MaxValue, default_startat (input));
}
public string Replace (string input, string replacement, int count)
{
- return Replace (input, replacement, count, RightToLeft ? input.Length : 0);
+ return Replace (input, replacement, count, default_startat (input));
}
public string Replace (string input, string replacement, int count, int startat)
{
+ if (input == null)
+ throw new ArgumentNullException ("input");
+ if (replacement == null)
+ throw new ArgumentNullException ("replacement");
+ if (count < -1)
+ throw new ArgumentOutOfRangeException ("count");
+ if (startat < 0 || startat > input.Length)
+ throw new ArgumentOutOfRangeException ("startat");
+
return CreateMachine ().Replace (this, input, replacement, count, startat);
}
public string [] Split (string input)
{
- return Split (input, Int32.MaxValue, RightToLeft ? input.Length : 0);
+ return Split (input, Int32.MaxValue, default_startat (input));
}
public string [] Split (string input, int count)
{
- return Split (input, count, RightToLeft ? input.Length : 0);
+ return Split (input, count, default_startat (input));
}
public string [] Split (string input, int count, int startat)
{
+ if (input == null)
+ throw new ArgumentNullException ("input");
+ if (count < 0)
+ throw new ArgumentOutOfRangeException ("count");
+ if (startat < 0 || startat > input.Length)
+ throw new ArgumentOutOfRangeException ("startat");
+
return CreateMachine ().Split (this, input, count, startat);
}
// expressions compiled to assemblies.
Init ();
}
-
+#if !NET_2_1
protected bool UseOptionC ()
{
return ((roptions & RegexOptions.Compiled) != 0);
}
-
+#endif
protected bool UseOptionR ()
{
return ((roptions & RegexOptions.RightToLeft) != 0);
get { return group_count; }
}
+ internal int Gap {
+ get { return gap; }
+ }
+
// private
private IMachine CreateMachine ()
private static string [] GetGroupNamesArray (int groupCount, IDictionary mapping)
{
- string [] groupNumberToNameMap = new string [groupCount + 1];
- foreach (string name in mapping.Keys) {
- groupNumberToNameMap [(int) mapping [name]] = name;
+ string [] group_names = new string [groupCount + 1];
+ IDictionaryEnumerator de = mapping.GetEnumerator ();
+ while (de.MoveNext ())
+ group_names [(int) de.Value] = (string) de.Key;
+ return group_names;
+ }
+
+ private int [] GroupNumbers {
+ get {
+ if (group_numbers == null) {
+ group_numbers = new int [1 + group_count];
+ for (int i = 0; i < gap; ++i)
+ group_numbers [i] = i;
+ for (int i = gap; i <= group_count; ++i)
+ group_numbers [i] = Int32.Parse (group_names [i]);
+ return group_numbers;
+ }
+ return group_numbers;
}
- return groupNumberToNameMap;
}
-
+
private IMachineFactory machineFactory;
private IDictionary mapping;
private int group_count;
+ private int gap;
private bool refsInitialized;
- private string [] _groupNumberToNameMap;
-
+ private string [] group_names;
+ private int [] group_numbers;
// protected members
// MS undocumented members
#if NET_2_1
[MonoTODO]
- protected internal System.Collections.Generic.Dictionary<string, int> capnames;
+ internal System.Collections.Generic.Dictionary<string, int> capnames;
[MonoTODO]
- protected internal System.Collections.Generic.Dictionary<int, int> caps;
+ internal System.Collections.Generic.Dictionary<int, int> caps;
#else
[MonoTODO]
protected internal System.Collections.Hashtable capnames;
[MonoTODO]
protected internal System.Collections.Hashtable caps;
+
+ [MonoTODO]
+ protected internal RegexRunnerFactory factory;
#endif
[MonoTODO]
protected internal int capsize;
[MonoTODO]
protected internal string [] capslist;
- [MonoTODO]
- protected internal RegexRunnerFactory factory;
}
}