public IgnoreCase(IgnoreCase? value)
		{
			if (value.HasValue)
				Value = value.Value;
			else
				Value = No.Value;
		}
		public static string EnsureReplace(this string cad,string search,string newstring,int minreplaces,out int totalreplaces,int maxreplaces = int.MaxValue,int fromindex=0,IgnoreCase? ignorecase=null)
		{
			if (minreplaces < 0) throw new ArgumentException("MinReplaces is negative.");
			if (minreplaces > maxreplaces) throw new ArgumentException("MinReplaces is greater than MaxReplaces.");
			var res = ReplaceCount(cad, search, newstring, out totalreplaces, maxreplaces, fromindex, ignorecase);
			if (totalreplaces < minreplaces) return null; else return res;
		}
		public static bool GetTokenRight(out string Token, IEnumerable<string> separator, ref string cad, IgnoreCase? ignorecase = null)
		{
			var p = cad.LastIndexOfSymbol(separator, ignorecase);
			if (p == null)
			{
				Token = null;
				return false;
			}
			Token = cad.Substring(p.Item1 + p.Item2.Length);
			cad = cad.Substring(0, p.Item1);
			return true;
		}
		public static int LastIndexOf(this string cad, IEnumerable<string> symbols, IgnoreCase? ignorecase = null)
		{
			var res = LastIndexOfSymbol(cad, symbols, ignorecase);
			return res?.Item1 ?? -1;
		}
		public static Tuple<int, string> LastIndexOfSymbol(this string cad, IEnumerable<string> symbols, IgnoreCase? ignorecase = null)
		{
			var res = symbols.Select(s => Tuple.Create(cad.LastIndexOf(s, new IgnoreCase(ignorecase)), s)).Where(i => i.Item1 >= 0).OrderByDescending(i => i.Item1).ToArray();
			if (res.Length <= 0) return null;
			return res[0];
		}
		public static string SymbolInPos(this string cad,int pos,IEnumerable<string> symbols,IgnoreCase? ignorecase=null)
		{
			if ((pos < 0) || (pos >= cad.Length)) return null;
			cad = cad.Substring(pos);
			foreach(var s in symbols)
			{
				if (cad.StartsWith(s,new IgnoreCase(ignorecase))) return s;
			}
			return null;
		}
		public static string RightToFar(this string cad, string left, bool forceifnotfound = false, IgnoreCase? ignorecase = null)
		{
			return _Between(cad, left, null, true,true, forceifnotfound, ignorecase);
		}
		private static string _Between(this string cad,string left,string right,bool farleft,bool farright,bool forceifnotfound=false, IgnoreCase? ignorecase=null)
		{
			if (string.IsNullOrEmpty(cad)) return null;
			var c = new IgnoreCase(ignorecase);
			var il = 0;
			var ir = cad.Length-1;
			if (!string.IsNullOrEmpty(left))
			{
				il = (farleft) ? cad.LastIndexOf(left,c) : cad.IndexOf(left,c);
				if (il >= 0)
					il += left.Length;
				else
					if (forceifnotfound) il = 0;
			}
			if (!string.IsNullOrEmpty(right))
			{
				ir = (farright)? cad.LastIndexOf(right, c):cad.IndexOf(right,c);
				if (ir >= 0)
					ir -= 1;
				else if (forceifnotfound) ir = cad.Length - 1;
			}
			if ((il < 0) || (ir < 0)) return null;
			return cad.Between(il, ir);
			
        }
		public static string RemoveMany(this string cad, string search, int maxreplaces, IgnoreCase? ignorecase=null) => cad.ReplaceN(search, "", maxreplaces, 0, ignorecase);
		public static string RemoveAll(this string cad, string search, int fromindex = 0, IgnoreCase? ignorecase = null) => cad.ReplaceN(search, "", int.MaxValue, fromindex, ignorecase);
		public static string RemoveAll(this string cad, string search, out int totalreplaces, IgnoreCase ignorecase) => cad.ReplaceCount(search, "", out totalreplaces, int.MaxValue, 0, ignorecase);
		public static string RemoveAll(this string cad, string search, out int totalreplaces,int fromindex = 0, IgnoreCase? ignorecase = null) => cad.ReplaceCount(search, "", out totalreplaces, int.MaxValue, fromindex, ignorecase);
		public static string ReplaceOne(this string cad, string search, string newstring, int fromindex = 0,IgnoreCase? ignorecase = null) => cad.ReplaceN(search, newstring,1,fromindex,ignorecase);
		public static string EnsureReplace(this string cad, string search, string newstring,IgnoreCase? ignorecase = null)
		{
			int t;
			return EnsureReplace(cad, search, newstring, 1, out t, int.MaxValue, 0, ignorecase);
		}
		public static string EnsureReplace(this string cad, string search, string newstring, out int totalreplaces, int maxreplaces = int.MaxValue, int fromindex = 0, IgnoreCase? ignorecase = null)
		{
			return EnsureReplace(cad, search, newstring, 1,out totalreplaces,maxreplaces, fromindex, ignorecase);
		}
		public static bool StartsWith(this string cad,string[] starts,bool trim=true,IgnoreCase? ignorecase=null)
		{
			var c = (trim) ? cad.TrimStart() : cad;
			foreach (var s in starts)
				if (c.StartsWith(s,new IgnoreCase(ignorecase))) return true;
			return false;
		}
		public static bool EndsWith(this string cad, string[] ends, bool trim = true,IgnoreCase? ignorecase=null)
		{
			var c = (trim) ? cad.TrimEnd() : cad;
			foreach (var s in ends)
				if (c.EndsWith(c,new IgnoreCase(null))) return true;
			return false;
		}
		public static string RemoveOne(this string cad, string search,  int fromindex = 0,IgnoreCase? ignorecase = null) => cad.RemoveMany(search,1, fromindex,ignorecase);
		public static string LeftTo(this string cad,string right,bool forceifnotfound=false,IgnoreCase? ignorecase= null)
		{
			return _Between(cad, null, right, false, false, forceifnotfound, ignorecase);
		}
		public static string RemoveOne(this string cad, string search, IgnoreCase ignorecase) => cad.RemoveMany(search, 1, 0, ignorecase);
		public static bool EqualsCase(this string cad,string other,IgnoreCase? ignorecase=null)
		{
			if (cad == null) return (other == null);
			return cad.Equals(other, new IgnoreCase(ignorecase));
		}
		public static string ReplaceLeft(this string cad,string search,string newstring,IgnoreCase ignorecase)
		{
			var Cad = cad ?? "";
			if (Cad.StartsWith(search, ignorecase))
				return newstring+Cad.Substring(search.Length);
			else
				return Cad;
		}
		public static string ReplaceAll(this string cad,IDictionary<string,string> dic,IgnoreCase? ignorecase= null)
		{
			foreach(var e in dic)
			{
				cad = cad.ReplaceAll(e.Key, e.Value, new IgnoreCase(ignorecase));
			}
			return cad;
		}
		public static string ReplaceRight(this string cad, string search, string newstring, IgnoreCase ignorecase)
		{
			var Cad = cad ?? "";
			if (Cad.EndsWith(search, ignorecase))
				return Cad.Substring(search.Length)+newstring;
			else
				return Cad;
		}
		public static string ReplaceOneRight(this string cad, string search, string newstring,IgnoreCase ignorecase,int fromindex=int.MaxValue)
		{
			if (string.IsNullOrEmpty(cad)) return cad??"";
			var p = cad.LastIndexOf(search,ignorecase);
			if (p >= fromindex) return cad;
			if (p>=0)
				return cad.Substring(0, p) + newstring + cad.Substring(p + search.Length);
			else
				return cad;
		}
		public static string RemoveRight(this string cad, string search, IgnoreCase ignorecase) => cad.ReplaceRight(search, "", ignorecase);
		public static Tuple<int, string> LastIndexOfSymbol(this string cad, string symbols, IgnoreCase? ignorecase = null) => LastIndexOfSymbol(cad, new[] { symbols }, ignorecase);
		public static string RemoveOneRight(this string cad, string search, IgnoreCase? ignorecase = null) => cad.ReplaceOneRight(search, "", new IgnoreCase(ignorecase));
		public static bool ContainsCase(this string cad,string search,IgnoreCase? ignorecase= null)
		{
			var p = cad.IndexOf(search, new IgnoreCase(ignorecase));
			return p >= 0;
		}
		public static string SafeReplace(this string cad, string search, string newstring, IgnoreCase ignorecase)
		{
			return ReplaceN(cad, search, newstring, int.MaxValue, 0, ignorecase);
		}