одиночные замены с параметром
This commit is contained in:
@@ -0,0 +1,256 @@
|
|||||||
|
namespace QWERTYkez.WordProcessor;
|
||||||
|
|
||||||
|
internal static class DynamicReplaceExt
|
||||||
|
{
|
||||||
|
// ============================================================
|
||||||
|
// Разбор шаблона вида "$key|$" на prefix="$key|" и suffix="$"
|
||||||
|
// Параметр помещается между prefix и suffix.
|
||||||
|
// ============================================================
|
||||||
|
internal static void ParsePattern(string oldValue, out string prefix, out string suffix)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(oldValue))
|
||||||
|
throw new ArgumentException("Old value cannot be null or empty", nameof(oldValue));
|
||||||
|
|
||||||
|
int lastPipe = oldValue.LastIndexOf('|');
|
||||||
|
if (lastPipe < 0)
|
||||||
|
throw new ArgumentException("Dynamic pattern must contain '|' separator", nameof(oldValue));
|
||||||
|
|
||||||
|
prefix = oldValue.Substring(0, lastPipe + 1);
|
||||||
|
suffix = oldValue.Substring(lastPipe + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal readonly struct MatchInfo(int start, int end, string param)
|
||||||
|
{
|
||||||
|
public readonly int Start = start;
|
||||||
|
public readonly int End = end;
|
||||||
|
public readonly string Param = param;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Поиск всех вхождений prefix + <param> + suffix в тексте.
|
||||||
|
// Возвращает список в порядке возрастания позиции.
|
||||||
|
// ============================================================
|
||||||
|
internal static List<MatchInfo> FindMatches(
|
||||||
|
string text,
|
||||||
|
string prefix,
|
||||||
|
string suffix,
|
||||||
|
StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
var result = new List<MatchInfo>();
|
||||||
|
if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(prefix))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
int searchPos = 0;
|
||||||
|
while (searchPos < text.Length)
|
||||||
|
{
|
||||||
|
int pStart = text.IndexOf(prefix, searchPos, comparisonType);
|
||||||
|
if (pStart < 0) break;
|
||||||
|
|
||||||
|
int paramStart = pStart + prefix.Length;
|
||||||
|
int pEnd;
|
||||||
|
if (string.IsNullOrEmpty(suffix))
|
||||||
|
{
|
||||||
|
pEnd = text.Length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pEnd = text.IndexOf(suffix, paramStart, comparisonType);
|
||||||
|
if (pEnd < 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
string param = text.Substring(paramStart, pEnd - paramStart);
|
||||||
|
int matchEnd = pEnd + suffix.Length;
|
||||||
|
result.Add(new MatchInfo(pStart, matchEnd, param));
|
||||||
|
|
||||||
|
// следующий поиск — после окончания текущего совпадения
|
||||||
|
searchPos = matchEnd;
|
||||||
|
if (searchPos <= pStart) searchPos = pStart + 1; // защита от зацикливания
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// REPLACE STRING (Func<string,string>)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
internal static void ReplaceStringInBody(
|
||||||
|
Body body, string oldValue, Func<string, string> factory, StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
if (body is null || factory is null) return;
|
||||||
|
ParsePattern(oldValue, out var prefix, out var suffix);
|
||||||
|
|
||||||
|
var paragraphs = body.Elements<Paragraph>().ToList();
|
||||||
|
for (int i = paragraphs.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
paragraphs[i].SimpleReplaceDynamic(prefix, suffix, factory, comparisonType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ReplaceStringInTables(
|
||||||
|
OpenXmlElement element, string oldValue, Func<string, string> factory, StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
if (element is null || factory is null) return;
|
||||||
|
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--)
|
||||||
|
{
|
||||||
|
paragraphs[i].SimpleReplaceDynamic(prefix, suffix, factory, comparisonType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ReplaceStringInHeadersFooters(
|
||||||
|
WordprocessingDocument doc, string oldValue, Func<string, string> factory, StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
if (doc is null || factory is null) return;
|
||||||
|
ParsePattern(oldValue, out var prefix, out var suffix);
|
||||||
|
|
||||||
|
foreach (var header in HeaderFooterProcessor.GetAllHeaders(doc))
|
||||||
|
ReplaceStringInElement(header, prefix, suffix, factory, comparisonType);
|
||||||
|
|
||||||
|
foreach (var footer in HeaderFooterProcessor.GetAllFooters(doc))
|
||||||
|
ReplaceStringInElement(footer, prefix, suffix, factory, comparisonType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReplaceStringInElement(
|
||||||
|
OpenXmlElement element, string prefix, string suffix,
|
||||||
|
Func<string, 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--)
|
||||||
|
{
|
||||||
|
allParagraphs[i].SimpleReplaceDynamic(prefix, suffix, factory, comparisonType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool SimpleReplaceDynamic(
|
||||||
|
this Paragraph? paragraph,
|
||||||
|
string prefix,
|
||||||
|
string suffix,
|
||||||
|
Func<string, string> factory,
|
||||||
|
StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
if (paragraph is null || factory is null) return false;
|
||||||
|
|
||||||
|
var text = paragraph.InnerText;
|
||||||
|
if (string.IsNullOrEmpty(text)) return false;
|
||||||
|
|
||||||
|
var matches = FindMatches(text, prefix, suffix, comparisonType);
|
||||||
|
if (matches.Count == 0) return false;
|
||||||
|
|
||||||
|
// Обходим справа налево: правые замены не сдвигают координаты левых.
|
||||||
|
for (int i = matches.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var m = matches[i];
|
||||||
|
string matchedText = text.Substring(m.Start, m.End - m.Start);
|
||||||
|
string replacement = factory(m.Param) ?? string.Empty;
|
||||||
|
|
||||||
|
paragraph.SimpleReplace(matchedText, replacement, comparisonType);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// REPLACE ITEM (Func<string,ReplaceItem>)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
internal static void ReplaceItemInBody(
|
||||||
|
Body body, string oldValue, Func<string, ReplaceItem> factory, StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
if (body is null || factory is null) return;
|
||||||
|
ParsePattern(oldValue, out var prefix, out var suffix);
|
||||||
|
|
||||||
|
var paragraphs = body.Elements<Paragraph>().ToList();
|
||||||
|
for (int i = paragraphs.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
paragraphs[i].SimpleReplaceItemDynamic(prefix, suffix, factory, comparisonType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ReplaceItemInTables(
|
||||||
|
OpenXmlElement element, string oldValue, Func<string, ReplaceItem> factory, StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
if (element is null || factory is null) return;
|
||||||
|
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--)
|
||||||
|
{
|
||||||
|
paragraphs[i].SimpleReplaceItemDynamic(prefix, suffix, factory, comparisonType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void ReplaceItemInHeadersFooters(
|
||||||
|
WordprocessingDocument doc, string oldValue, Func<string, ReplaceItem> factory, StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
if (doc is null || factory is null) return;
|
||||||
|
ParsePattern(oldValue, out var prefix, out var suffix);
|
||||||
|
|
||||||
|
foreach (var header in HeaderFooterProcessor.GetAllHeaders(doc))
|
||||||
|
ReplaceItemInElement(header, prefix, suffix, factory, comparisonType);
|
||||||
|
|
||||||
|
foreach (var footer in HeaderFooterProcessor.GetAllFooters(doc))
|
||||||
|
ReplaceItemInElement(footer, prefix, suffix, factory, comparisonType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReplaceItemInElement(
|
||||||
|
OpenXmlElement element, string prefix, string suffix,
|
||||||
|
Func<string, 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--)
|
||||||
|
{
|
||||||
|
allParagraphs[i].SimpleReplaceItemDynamic(prefix, suffix, factory, comparisonType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool SimpleReplaceItemDynamic(
|
||||||
|
this Paragraph? paragraph,
|
||||||
|
string prefix,
|
||||||
|
string suffix,
|
||||||
|
Func<string, ReplaceItem> factory,
|
||||||
|
StringComparison comparisonType)
|
||||||
|
{
|
||||||
|
if (paragraph is null || factory is null) return false;
|
||||||
|
|
||||||
|
var text = paragraph.InnerText;
|
||||||
|
if (string.IsNullOrEmpty(text)) return false;
|
||||||
|
|
||||||
|
var matches = FindMatches(text, prefix, suffix, comparisonType);
|
||||||
|
if (matches.Count == 0) return false;
|
||||||
|
|
||||||
|
for (int i = matches.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var m = matches[i];
|
||||||
|
string matchedText = text.Substring(m.Start, m.End - m.Start);
|
||||||
|
|
||||||
|
ReplaceItem item = factory(m.Param);
|
||||||
|
if (item is null) continue;
|
||||||
|
|
||||||
|
if (item.BreakValue.HasValue)
|
||||||
|
{
|
||||||
|
// Поддерживаются PageBreak / NewLandscapeSection / NewPortraitSection
|
||||||
|
paragraph.SimpleReplace(matchedText, string.Empty, comparisonType, item.BreakValue.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
paragraph.SimpleReplace(matchedText, item.Text ?? string.Empty, comparisonType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
namespace QWERTYkez.WordProcessor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Вспомогательный класс для динамической замены параграфов, содержащих "$key|param$",
|
||||||
|
/// на текст, построенный через <see cref="IText"/>.
|
||||||
|
/// </summary>
|
||||||
|
internal static class DynamicReplaceToTextExt
|
||||||
|
{
|
||||||
|
internal static void ReplaceParagraphsContainingTextToTextDynamic(
|
||||||
|
Body body,
|
||||||
|
string oldValue,
|
||||||
|
Action<string, IText> buildText)
|
||||||
|
{
|
||||||
|
if (body is null || string.IsNullOrEmpty(oldValue) || buildText is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DynamicReplaceExt.ParsePattern(oldValue, out var prefix, out var suffix);
|
||||||
|
|
||||||
|
var paragraphs = body.Elements<Paragraph>().ToList();
|
||||||
|
if (paragraphs.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (int i = paragraphs.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var paragraph = paragraphs[i];
|
||||||
|
if (paragraph is null) continue;
|
||||||
|
|
||||||
|
var paraText = paragraph.InnerText;
|
||||||
|
if (string.IsNullOrEmpty(paraText)) continue;
|
||||||
|
|
||||||
|
int pStart = paraText.IndexOf(prefix, StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (pStart < 0) continue;
|
||||||
|
|
||||||
|
int paramStart = pStart + prefix.Length;
|
||||||
|
int pEnd = string.IsNullOrEmpty(suffix)
|
||||||
|
? paraText.Length
|
||||||
|
: paraText.IndexOf(suffix, paramStart, StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (pEnd < 0) continue;
|
||||||
|
|
||||||
|
string param = paraText.Substring(paramStart, pEnd - paramStart);
|
||||||
|
string matchedText = paraText.Substring(pStart, pEnd + suffix.Length - pStart);
|
||||||
|
|
||||||
|
var fontProps = ExtractFontPropsFromParagraph(paragraph, matchedText);
|
||||||
|
var paragraphProps = paragraph.ParagraphProperties?.CloneNode(true) as ParagraphProperties;
|
||||||
|
|
||||||
|
var capturedParam = param;
|
||||||
|
ReplaceWithTextBuilder(paragraph, tb => buildText(capturedParam, tb), fontProps, paragraphProps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Ниже — 1:1 копия из ReplaceToTextExt (private helper-методы)
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
|
||||||
|
private static void ReplaceWithTextBuilder(
|
||||||
|
Paragraph paragraph,
|
||||||
|
Action<IText> buildText,
|
||||||
|
FontProps? baseFont,
|
||||||
|
ParagraphProperties? baseParagraphProps)
|
||||||
|
{
|
||||||
|
if (paragraph is null || paragraph.Parent is null || buildText is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var parent = paragraph.Parent;
|
||||||
|
|
||||||
|
var builder = TextBuilder.Create(baseFont, baseParagraphProps);
|
||||||
|
buildText(builder);
|
||||||
|
var newParagraphs = builder.Build();
|
||||||
|
|
||||||
|
int paraIndex = -1;
|
||||||
|
var children = parent.ChildElements;
|
||||||
|
|
||||||
|
for (int i = 0; i < children.Count; i++)
|
||||||
|
{
|
||||||
|
if (children[i] == paragraph)
|
||||||
|
{
|
||||||
|
paraIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paraIndex == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
parent.RemoveChild(paragraph);
|
||||||
|
|
||||||
|
for (int i = 0; i < newParagraphs.Count; i++)
|
||||||
|
{
|
||||||
|
parent.InsertAt(newParagraphs[i], paraIndex + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FontProps? ExtractFontPropsFromParagraph(Paragraph paragraph, string searchText)
|
||||||
|
{
|
||||||
|
if (paragraph is null || string.IsNullOrEmpty(searchText))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var runs = paragraph.Descendants<Run>().ToList();
|
||||||
|
if (runs.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var runInfos = new List<(Run Run, int Start, int End, string Text)>();
|
||||||
|
int currentPosition = 0;
|
||||||
|
|
||||||
|
foreach (var run in runs)
|
||||||
|
{
|
||||||
|
var runText = GetRunText(run);
|
||||||
|
if (!string.IsNullOrEmpty(runText))
|
||||||
|
{
|
||||||
|
runInfos.Add((run, currentPosition, currentPosition + runText.Length, runText));
|
||||||
|
currentPosition += runText.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (run, start, end, text) in runInfos)
|
||||||
|
{
|
||||||
|
if (text.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
{
|
||||||
|
return CreateFontPropsFromRun(run);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fullText = string.Concat(runInfos.Select(r => r.Text));
|
||||||
|
int textIndex = fullText.IndexOf(searchText, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (textIndex >= 0)
|
||||||
|
{
|
||||||
|
var intersectingRun = runInfos.FirstOrDefault(r =>
|
||||||
|
r.Start <= textIndex && r.End > textIndex);
|
||||||
|
|
||||||
|
if (intersectingRun.Run is not null)
|
||||||
|
{
|
||||||
|
return CreateFontPropsFromRun(intersectingRun.Run);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FontProps CreateFontPropsFromRun(Run run)
|
||||||
|
{
|
||||||
|
var runProperties = run.RunProperties;
|
||||||
|
if (runProperties is null)
|
||||||
|
return new FontProps();
|
||||||
|
|
||||||
|
var fontProps = new FontProps();
|
||||||
|
|
||||||
|
var runFonts = runProperties.GetFirstChild<RunFonts>();
|
||||||
|
if (runFonts is not null)
|
||||||
|
{
|
||||||
|
fontProps = fontProps with
|
||||||
|
{
|
||||||
|
FontFamily = runFonts.Ascii ?? runFonts.HighAnsi ?? runFonts.ComplexScript
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var fontSize = runProperties.GetFirstChild<FontSize>();
|
||||||
|
if (fontSize is not null && !string.IsNullOrEmpty(fontSize.Val) &&
|
||||||
|
uint.TryParse(fontSize.Val, out uint halfPoints))
|
||||||
|
{
|
||||||
|
fontProps = fontProps with { Size = halfPoints / 2.0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
var bold = runProperties.GetFirstChild<Bold>();
|
||||||
|
if (bold is not null)
|
||||||
|
{
|
||||||
|
bool isBold = true;
|
||||||
|
if (bold.Val is not null)
|
||||||
|
isBold = bold.Val.Value;
|
||||||
|
fontProps = fontProps with { IsBold = isBold };
|
||||||
|
}
|
||||||
|
|
||||||
|
var italic = runProperties.GetFirstChild<Italic>();
|
||||||
|
if (italic is not null)
|
||||||
|
{
|
||||||
|
bool isItalic = true;
|
||||||
|
if (italic.Val is not null)
|
||||||
|
isItalic = italic.Val.Value;
|
||||||
|
fontProps = fontProps with { IsItalic = isItalic };
|
||||||
|
}
|
||||||
|
|
||||||
|
var underline = runProperties.GetFirstChild<Underline>();
|
||||||
|
if (underline is not null && underline.Val is not null)
|
||||||
|
{
|
||||||
|
fontProps = fontProps with { Underline = underline.Val.Value };
|
||||||
|
}
|
||||||
|
|
||||||
|
var color = runProperties.GetFirstChild<Color>();
|
||||||
|
if (color is not null && !string.IsNullOrEmpty(color.Val))
|
||||||
|
{
|
||||||
|
fontProps = fontProps with { Color = color.Val };
|
||||||
|
}
|
||||||
|
|
||||||
|
var verticalAlignment = runProperties.GetFirstChild<VerticalTextAlignment>();
|
||||||
|
if (verticalAlignment is not null && verticalAlignment.Val is not null)
|
||||||
|
{
|
||||||
|
fontProps = fontProps with { SubSup = verticalAlignment.Val.Value };
|
||||||
|
}
|
||||||
|
|
||||||
|
return fontProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetRunText(Run run)
|
||||||
|
{
|
||||||
|
if (run is null) return string.Empty;
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var text in run.Elements<Text>())
|
||||||
|
{
|
||||||
|
sb.Append(text.Text ?? string.Empty);
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -337,6 +337,135 @@ internal sealed class WordWriter : WordReader, IWordWriter
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void ReplaceString(string oldValue, Func<string, string> newValues)
|
||||||
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(oldValue))
|
||||||
|
throw new ArgumentException("Old value cannot be null or empty", nameof(oldValue));
|
||||||
|
|
||||||
|
if (newValues is null) return;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Debug.WriteLine($"[DEBUG] [WordProcessor.ReplaceString(dynamic)] START: '{oldValue}'");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lock (_syncLock)
|
||||||
|
{
|
||||||
|
// 1. Основной текст
|
||||||
|
DynamicReplaceExt.ReplaceStringInBody(_body, oldValue, newValues, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// 2. Таблицы в основном тексте
|
||||||
|
DynamicReplaceExt.ReplaceStringInTables(_body, oldValue, newValues, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// 3. Колонтитулы
|
||||||
|
DynamicReplaceExt.ReplaceStringInHeadersFooters(_doc, oldValue, newValues, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
_isModified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceItem(string oldValue, Func<string, ReplaceItem> newValues)
|
||||||
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(oldValue))
|
||||||
|
throw new ArgumentException("Old value cannot be null or empty", nameof(oldValue));
|
||||||
|
|
||||||
|
if (newValues is null) return;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Debug.WriteLine($"[DEBUG] [WordProcessor.ReplaceItem(dynamic)] START: '{oldValue}'");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lock (_syncLock)
|
||||||
|
{
|
||||||
|
// 1. Основной текст
|
||||||
|
DynamicReplaceExt.ReplaceItemInBody(_body, oldValue, newValues, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// 2. Таблицы в основном тексте
|
||||||
|
DynamicReplaceExt.ReplaceItemInTables(_body, oldValue, newValues, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
// 3. Колонтитулы
|
||||||
|
DynamicReplaceExt.ReplaceItemInHeadersFooters(_doc, oldValue, newValues, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
_isModified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceToText(string oldValue, Action<string, IText> buildText)
|
||||||
|
{
|
||||||
|
ThrowIfDisposed();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(oldValue))
|
||||||
|
throw new ArgumentException("Old value cannot be null or empty", nameof(oldValue));
|
||||||
|
|
||||||
|
if (buildText is null) return;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
Debug.WriteLine($"[DEBUG] [WordProcessor.ReplaceToText(dynamic)] START: '{oldValue}'");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lock (_syncLock)
|
||||||
|
{
|
||||||
|
DynamicReplaceToTextExt.ReplaceParagraphsContainingTextToTextDynamic(_body, oldValue, buildText);
|
||||||
|
_isModified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public void ReplaceString(string oldValue, Func<string, IEnumerable<string>> newValues)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceString(string oldValue, Func<string, string[]> newValues)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceItem(string oldValue, Func<string, IEnumerable<ReplaceItem>> newValues)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceItem(string oldValue, Func<string, ReplaceItem[]> newValues)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceToTable(string oldValue, Action<string, ITable> buildTable)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplaceToTable(string oldValue, FontProps baseFont, Action<string, ITable> buildTable)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Добавляет новый параграф с указанным текстом в конец документа.
|
/// Добавляет новый параграф с указанным текстом в конец документа.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user