Files
QWERTYkez.OpenXmlProcessors/QWERTYkez.WordProcessor/DynamicMultiReplaceExt.cs
T

219 lines
8.8 KiB
C#

namespace QWERTYkez.WordProcessor;
/// <summary>
/// Множественные динамические замены с извлечением параметра из "$key|param$".
/// Переиспользует движок <see cref="MultiReplaceExt"/>
/// </summary>
internal static class DynamicMultiReplaceExt
{
// ============================================================
// ReplaceString (Func<string, IEnumerable<string>>)
// ============================================================
internal static void ReplaceStringMultiInBody(
Body body,
string oldValue,
Func<string, IEnumerable<string>> factory,
StringComparison comparisonType)
{
if (body is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
var paragraphs = body.Elements<Paragraph>().ToList();
for (int i = paragraphs.Count - 1; i >= 0; i--)
ProcessDynamicStringMulti(paragraphs[i], prefix, suffix, factory, comparisonType);
}
internal static void ReplaceStringMultiInTables(
OpenXmlElement element,
string oldValue,
Func<string, IEnumerable<string>> factory,
StringComparison comparisonType)
{
if (element is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
foreach (var table in TableTextProcessor.GetAllTables(element))
{
var paragraphs = TableTextProcessor.GetTableParagraphs(table).ToList();
for (int i = paragraphs.Count - 1; i >= 0; i--)
ProcessDynamicStringMulti(paragraphs[i], prefix, suffix, factory, comparisonType);
}
}
internal static void ReplaceStringMultiInHeadersFooters(
WordprocessingDocument doc,
string oldValue,
Func<string, IEnumerable<string>> factory,
StringComparison comparisonType)
{
if (doc is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
foreach (var header in HeaderFooterProcessor.GetAllHeaders(doc))
ProcessStringMultiInElement(header, prefix, suffix, factory, comparisonType);
foreach (var footer in HeaderFooterProcessor.GetAllFooters(doc))
ProcessStringMultiInElement(footer, prefix, suffix, factory, comparisonType);
}
private static void ProcessStringMultiInElement(
OpenXmlElement element,
string prefix,
string suffix,
Func<string, IEnumerable<string>> factory,
StringComparison comparisonType)
{
var paragraphs = element.Descendants<Paragraph>().ToList();
var tables = TableTextProcessor.GetAllTables(element).ToList();
var tableParagraphs = tables.SelectMany(t => TableTextProcessor.GetTableParagraphs(t)).ToList();
var allParagraphs = paragraphs.Concat(tableParagraphs).Distinct().ToList();
for (int i = allParagraphs.Count - 1; i >= 0; i--)
ProcessDynamicStringMulti(allParagraphs[i], prefix, suffix, factory, comparisonType);
}
private static void ProcessDynamicStringMulti(
Paragraph paragraph,
string prefix,
string suffix,
Func<string, IEnumerable<string>> factory,
StringComparison comparisonType)
{
if (paragraph is null || paragraph.Parent is null) return;
var text = paragraph.InnerText;
if (string.IsNullOrEmpty(text)) return;
var matches = DynamicReplaceExt.FindMatches(text, prefix, suffix, comparisonType);
if (matches.Count == 0) return;
// Строим словарь уникальных matchedText -> значения для этого параграфа
var dict = new Dictionary<string, IEnumerable<string>>();
for (int i = 0; i < matches.Count; i++)
{
var m = matches[i];
string matchedText = text.Substring(m.Start, m.End - m.Start);
if (dict.ContainsKey(matchedText)) continue;
IEnumerable<string> values;
try { values = factory(m.Param); }
catch { continue; }
if (values is null) continue;
var list = values as IList<string> ?? [.. values];
if (list.Count == 0) continue;
dict[matchedText] = list;
}
if (dict.Count == 0) return;
var newParas = MultiReplaceExt.ProcessParagraphWithMergedBoundaries(paragraph, dict, comparisonType);
if (newParas is not null && newParas.Count > 0)
ParagraphReplacer.ReplaceParagraph(paragraph, newParas);
}
// ============================================================
// ReplaceItem (Func<string, IEnumerable<ReplaceItem>>)
// ============================================================
internal static void ReplaceItemMultiInBody(
Body body,
string oldValue,
Func<string, IEnumerable<ReplaceItem>> factory,
StringComparison comparisonType)
{
if (body is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
var paragraphs = body.Elements<Paragraph>().ToList();
for (int i = paragraphs.Count - 1; i >= 0; i--)
ProcessDynamicItemMulti(paragraphs[i], prefix, suffix, factory, comparisonType);
}
internal static void ReplaceItemMultiInTables(
OpenXmlElement element,
string oldValue,
Func<string, IEnumerable<ReplaceItem>> factory,
StringComparison comparisonType)
{
if (element is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
foreach (var table in TableTextProcessor.GetAllTables(element))
{
var paragraphs = TableTextProcessor.GetTableParagraphs(table).ToList();
for (int i = paragraphs.Count - 1; i >= 0; i--)
ProcessDynamicItemMulti(paragraphs[i], prefix, suffix, factory, comparisonType);
}
}
internal static void ReplaceItemMultiInHeadersFooters(
WordprocessingDocument doc,
string oldValue,
Func<string, IEnumerable<ReplaceItem>> factory,
StringComparison comparisonType)
{
if (doc is null || factory is null) return;
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
foreach (var header in HeaderFooterProcessor.GetAllHeaders(doc))
ProcessItemMultiInElement(header, prefix, suffix, factory, comparisonType);
foreach (var footer in HeaderFooterProcessor.GetAllFooters(doc))
ProcessItemMultiInElement(footer, prefix, suffix, factory, comparisonType);
}
private static void ProcessItemMultiInElement(
OpenXmlElement element,
string prefix,
string suffix,
Func<string, IEnumerable<ReplaceItem>> factory,
StringComparison comparisonType)
{
var paragraphs = element.Descendants<Paragraph>().ToList();
var tables = TableTextProcessor.GetAllTables(element).ToList();
var tableParagraphs = tables.SelectMany(t => TableTextProcessor.GetTableParagraphs(t)).ToList();
var allParagraphs = paragraphs.Concat(tableParagraphs).Distinct().ToList();
for (int i = allParagraphs.Count - 1; i >= 0; i--)
ProcessDynamicItemMulti(allParagraphs[i], prefix, suffix, factory, comparisonType);
}
private static void ProcessDynamicItemMulti(
Paragraph paragraph,
string prefix,
string suffix,
Func<string, IEnumerable<ReplaceItem>> factory,
StringComparison comparisonType)
{
if (paragraph is null || paragraph.Parent is null) return;
var text = paragraph.InnerText;
if (string.IsNullOrEmpty(text)) return;
var matches = DynamicReplaceExt.FindMatches(text, prefix, suffix, comparisonType);
if (matches.Count == 0) return;
var dict = new Dictionary<string, IEnumerable<ReplaceItem>>();
for (int i = 0; i < matches.Count; i++)
{
var m = matches[i];
string matchedText = text.Substring(m.Start, m.End - m.Start);
if (dict.ContainsKey(matchedText)) continue;
IEnumerable<ReplaceItem> values;
try { values = factory(m.Param); }
catch { continue; }
if (values is null) continue;
var list = values as IList<ReplaceItem> ?? [.. values];
if (list.Count == 0) continue;
dict[matchedText] = list;
}
if (dict.Count == 0) return;
var newParas = MultiReplaceExt.ProcessParagraphWithMergedBoundaries(paragraph, dict, comparisonType);
if (newParas is not null && newParas.Count > 0)
ParagraphReplacer.ReplaceParagraph(paragraph, newParas);
}
}