множественные замены с параметром
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
namespace QWERTYkez.WordProcessor;
|
||||
|
||||
/// <summary>
|
||||
/// Множественные динамические замены с извлечением параметра из "$key|param$".
|
||||
/// Переиспользует движок <see cref="MultiReplaceExt"/> (форматирование Run-ов,
|
||||
/// разрывы страниц, смена ориентации, разбиение на параграфы — всё как в оригинале).
|
||||
/// </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.ToList();
|
||||
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.ToList();
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user