Send to your Kindle using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Text; using System.Text.RegularExpressions; using System.Diagnostics; using System.Reflection; namespace X03.PageElements.Notations { abstract public class Nestable : PageElements.Notation, Plugin.PageElement { new static public IEnumerable<Type> GetPluginClasses() { return Utils.GetPluginClasses(typeof(PageElements.Notations.Nestable)); } private static PageElement createNestableElement(Type notationClass, PageElement parent, List<PageElement> children) { return (PageElement)Assembly.GetAssembly(notationClass).CreateInstance(notationClass.FullName, false, BindingFlags.CreateInstance, null, new object[] { parent, children }, null, null); } public static List<PageElement> Generate(Type notationClass, PageElement parent, List<PageElement> elements, HashSet<Type> targetClasses) { var ret = new List<PageElement>(elements); var patterns = notationClass.GetField("Patterns", BindingFlags.Static | BindingFlags.Public).GetValue(null) as string[]; if (patterns == null || patterns.Length < 2) return ret; var beginElementIndexes = new Stack<int>(); var beginMatchGroups = new Stack<Group>(); PageElement mergeTarget = null; Match m = null; var idx = 0; while (idx <= ret.Count - 1) { if (ret[idx] is PageElements.Wikitext) { PageElements.Wikitext wikitext = ret[idx] as PageElements.Wikitext; m = Regex.Match(wikitext.ToWikitext(), @"(?<begin>" + patterns[0] + @")|(?<end>" + patterns[1] + @")", RegexOptions.Singleline | RegexOptions.IgnoreCase); while (m.Success) { Debug.Assert(ret[idx] is PageElements.Wikitext); if (m.Groups["begin"].Success) { // begin発見 beginElementIndexes.Push(idx); beginMatchGroups.Push(m.Groups["begin"]); } else if (m.Groups["end"].Success && beginElementIndexes.Count >= 1 && beginMatchGroups.Count >= 1) { // end発見→PageElement生成 Group beginMatchGroup; int beginElementIndex; int beginStringIndex; int beginStringLength; int endElementIndex; int endStringIndex; int endStringLength; { // idx用意 beginMatchGroup = beginMatchGroups.Pop(); beginElementIndex = beginElementIndexes.Pop(); beginStringIndex = beginMatchGroup.Index; beginStringLength = beginMatchGroup.Length; endElementIndex = idx; endStringIndex = m.Groups["end"].Captures[0].Index; endStringLength = m.Groups["end"].Captures[0].Length; } var additions = new List<PageElement>(); { // 退避 ret.GetRange() -> additions, ret.RemoveRange() additions.AddRange(ret.GetRange(beginElementIndex, endElementIndex - beginElementIndex + 1)); ret.RemoveRange(beginElementIndex, endElementIndex - beginElementIndex + 1); idx = beginElementIndex - 1; //endElementIndex = -1; } { Debug.Assert(beginElementIndex <= endElementIndex); var subs = new string[6] { "", "", "", "", "", "" }; { // additions.First()を3分割 // additions.Last()を3分割 Debug.Assert(additions.First() is PageElements.Wikitext); Debug.Assert(additions.Last() is PageElements.Wikitext); var first = ((PageElements.Wikitext)additions.First()).ToWikitext(); var last = ((PageElements.Wikitext)additions.Last()).ToWikitext(); subs[0] = first.Substring(0, beginStringIndex - 1 + 1); subs[1] = first.Substring(beginStringIndex, beginStringLength); if (beginElementIndex == endElementIndex) { subs[2] = ""; subs[3] = last.Substring(beginStringIndex + beginStringLength, (endStringIndex - 1) - (beginStringIndex + beginStringLength) + 1); } else { subs[2] = first.Substring(beginStringIndex + beginStringLength); subs[3] = last.Substring(0, endStringIndex - 1 + 1); } subs[4] = last.Substring(endStringIndex, endStringLength); subs[5] = last.Substring(endStringIndex + endStringLength); Debug.Print("subs: {0}, first: {1}, last: {2}", subs.Sum(x => x.Length), first.Length, last.Length); if (beginElementIndex == endElementIndex) Debug.Assert(subs.Sum(x => x.Length) == first.Length && subs.Sum(x => x.Length) == last.Length); else Debug.Assert(subs.Sum(x => x.Length) == first.Length + last.Length); } { { // additions:retに追加する分 if (beginElementIndex == endElementIndex) { additions.Remove(additions.First()); Debug.Assert(additions.Count == 0); } else { additions.Remove(additions.First()); additions.Remove(additions.Last()); } if (subs[2].Length > 0) additions.Insert(0, new PageElements.Wikitext(subs[2])); Debug.Assert(subs[1] == beginMatchGroup.Value); additions.Insert(0, new PageElements.Affix(parent, subs[1])); // m[begin].Value if (subs[3].Length > 0) additions.Add(new PageElements.Wikitext(subs[3])); Debug.Assert(subs[4] == m.Value); additions.Add(new PageElements.Affix(parent, subs[4])); // m[end].Value } if (subs[5].Length > 0) { ret.Insert(beginElementIndex, new PageElements.Wikitext(subs[5])); idx++; } if (notationClass.GetMethod("Merge") != null) { if (beginStringIndex == 0 && mergeTarget != null && mergeTarget.GetType().Name == notationClass.Name) { // 連結(既存インスタンスと統合)。新しいインスタンスは生成しない。 notationClass.GetMethod("Merge").Invoke(null, new object[] { parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses), mergeTarget }); //mergeTarget はそのまま } else { // createElement mergeTarget = createNestableElement(notationClass, parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses)); ret.Insert(beginElementIndex, mergeTarget); idx++; } } else { // createElement ret.Insert(beginElementIndex, createNestableElement(notationClass, parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses))); idx++; } if (subs[0].Length > 0) { ret.Insert(beginElementIndex, new PageElements.Wikitext(subs[0])); idx++; } } idx--; // 追加された最後の要素を指すように、直後に実行されるidx++に合わせて調整 break; //continue; } } else { //Debug.Fail(m.Value); } m = m.NextMatch(); } } else { } idx++; } return ret; } public override void Accept(PageElementVisitor visitor) { throw new NotImplementedException(); } public override void InAction() { throw new NotImplementedException(); } public override string CreateTag() { throw new NotImplementedException(); } public static string[] Patterns; public Nestable(PageElement parent, List<PageElement> children) : base(parent, children) { } } } using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Text; using System.Text.RegularExpressions; using System.Diagnostics; using System.Reflection; namespace X03.PageElements.Notations { abstract public class Nestable : PageElements.Notation, Plugin.PageElement { new static public IEnumerable<Type> GetPluginClasses() { return Utils.GetPluginClasses(typeof(PageElements.Notations.Nestable)); } private static PageElement createNestableElement(Type notationClass, PageElement parent, List<PageElement> children) { return (PageElement)Assembly.GetAssembly(notationClass).CreateInstance(notationClass.FullName, false, BindingFlags.CreateInstance, null, new object[] { parent, children }, null, null); } public static List<PageElement> Generate(Type notationClass, PageElement parent, List<PageElement> elements, HashSet<Type> targetClasses) { var ret = new List<PageElement>(elements); var patterns = notationClass.GetField("Patterns", BindingFlags.Static | BindingFlags.Public).GetValue(null) as string[]; if (patterns == null || patterns.Length < 2) return ret; var beginElementIndexes = new Stack<int>(); var beginMatchGroups = new Stack<Group>(); PageElement mergeTarget = null; Match m = null; var idx = 0; while (idx <= ret.Count - 1) { if (ret[idx] is PageElements.Wikitext) { PageElements.Wikitext wikitext = ret[idx] as PageElements.Wikitext; m = Regex.Match(wikitext.ToWikitext(), @"(?<begin>" + patterns[0] + @")|(?<end>" + patterns[1] + @")", RegexOptions.Singleline | RegexOptions.IgnoreCase); while (m.Success) { Debug.Assert(ret[idx] is PageElements.Wikitext); if (m.Groups["begin"].Success) { // begin発見 beginElementIndexes.Push(idx); beginMatchGroups.Push(m.Groups["begin"]); } else if (m.Groups["end"].Success && beginElementIndexes.Count >= 1 && beginMatchGroups.Count >= 1) { // end発見→PageElement生成 Group beginMatchGroup; int beginElementIndex; int beginStringIndex; int beginStringLength; int endElementIndex; int endStringIndex; int endStringLength; { // idx用意 beginMatchGroup = beginMatchGroups.Pop(); beginElementIndex = beginElementIndexes.Pop(); beginStringIndex = beginMatchGroup.Index; beginStringLength = beginMatchGroup.Length; endElementIndex = idx; endStringIndex = m.Groups["end"].Captures[0].Index; endStringLength = m.Groups["end"].Captures[0].Length; } var additions = new List<PageElement>(); { // 退避 ret.GetRange() -> additions, ret.RemoveRange() additions.AddRange(ret.GetRange(beginElementIndex, endElementIndex - beginElementIndex + 1)); ret.RemoveRange(beginElementIndex, endElementIndex - beginElementIndex + 1); idx = beginElementIndex - 1; //endElementIndex = -1; } { Debug.Assert(beginElementIndex <= endElementIndex); var subs = new string[6] { "", "", "", "", "", "" }; { // additions.First()を3分割 // additions.Last()を3分割 Debug.Assert(additions.First() is PageElements.Wikitext); Debug.Assert(additions.Last() is PageElements.Wikitext); var first = ((PageElements.Wikitext)additions.First()).ToWikitext(); var last = ((PageElements.Wikitext)additions.Last()).ToWikitext(); subs[0] = first.Substring(0, beginStringIndex - 1 + 1); subs[1] = first.Substring(beginStringIndex, beginStringLength); if (beginElementIndex == endElementIndex) { subs[2] = ""; subs[3] = last.Substring(beginStringIndex + beginStringLength, (endStringIndex - 1) - (beginStringIndex + beginStringLength) + 1); } else { subs[2] = first.Substring(beginStringIndex + beginStringLength); subs[3] = last.Substring(0, endStringIndex - 1 + 1); } subs[4] = last.Substring(endStringIndex, endStringLength); subs[5] = last.Substring(endStringIndex + endStringLength); Debug.Print("subs: {0}, first: {1}, last: {2}", subs.Sum(x => x.Length), first.Length, last.Length); if (beginElementIndex == endElementIndex) Debug.Assert(subs.Sum(x => x.Length) == first.Length && subs.Sum(x => x.Length) == last.Length); else Debug.Assert(subs.Sum(x => x.Length) == first.Length + last.Length); } { { // additions:retに追加する分 if (beginElementIndex == endElementIndex) { additions.Remove(additions.First()); Debug.Assert(additions.Count == 0); } else { additions.Remove(additions.First()); additions.Remove(additions.Last()); } if (subs[2].Length > 0) additions.Insert(0, new PageElements.Wikitext(subs[2])); Debug.Assert(subs[1] == beginMatchGroup.Value); additions.Insert(0, new PageElements.Affix(parent, subs[1])); // m[begin].Value if (subs[3].Length > 0) additions.Add(new PageElements.Wikitext(subs[3])); Debug.Assert(subs[4] == m.Value); additions.Add(new PageElements.Affix(parent, subs[4])); // m[end].Value } if (subs[5].Length > 0) { ret.Insert(beginElementIndex, new PageElements.Wikitext(subs[5])); idx++; } if (notationClass.GetMethod("Merge") != null) { if (beginStringIndex == 0 && mergeTarget != null && mergeTarget.GetType().Name == notationClass.Name) { // 連結(既存インスタンスと統合)。新しいインスタンスは生成しない。 notationClass.GetMethod("Merge").Invoke(null, new object[] { parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses), mergeTarget }); //mergeTarget はそのまま } else { // createElement mergeTarget = createNestableElement(notationClass, parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses)); ret.Insert(beginElementIndex, mergeTarget); idx++; } } else { // createElement ret.Insert(beginElementIndex, createNestableElement(notationClass, parent, PageElements.Wikitext.Tokenize(parent, additions, targetClasses))); idx++; } if (subs[0].Length > 0) { ret.Insert(beginElementIndex, new PageElements.Wikitext(subs[0])); idx++; } } idx--; // 追加された最後の要素を指すように、直後に実行されるidx++に合わせて調整 break; //continue; } } else { //Debug.Fail(m.Value); } m = m.NextMatch(); } } else { } idx++; } return ret; } public override void Accept(PageElementVisitor visitor) { throw new NotImplementedException(); } public override void InAction() { throw new NotImplementedException(); } public override string CreateTag() { throw new NotImplementedException(); } public static string[] Patterns; public Nestable(PageElement parent, List<PageElement> children) : base(parent, children) { } } }