This commit is contained in:
melekhin
2026-07-21 16:43:59 +07:00
parent 5302edfb8f
commit 1dcb22e1d5
8 changed files with 306 additions and 126 deletions
+60 -26
View File
@@ -9,7 +9,7 @@ internal static class SimplyReplaceExt
internal readonly int Length = length;
}
private sealed class ParagraphStructure(string fullText, SimplyReplaceExt.TextNodeInfo[] textNodes)
private sealed class ParagraphStructure(string fullText, TextNodeInfo[] textNodes)
{
internal readonly string FullText = fullText;
internal readonly TextNodeInfo[] TextNodes = textNodes;
@@ -77,7 +77,7 @@ internal static class SimplyReplaceExt
}
}
internal static bool SimpleReplace(this Paragraph? paragraph, string oldValue, string newValue, StringComparison comparisonType, bool breakPage = false)
internal static bool SimpleReplace(this Paragraph? paragraph, string oldValue, string newValue, StringComparison comparisonType, PageBreakType splitValue = PageBreakType.None)
{
if (paragraph is null || string.IsNullOrEmpty(oldValue))
return false;
@@ -103,10 +103,13 @@ internal static class SimplyReplaceExt
if (nodesToReplace.Count == 0)
return false;
ExecuteReplacement(nodesToReplace, matchIndex, matchEnd, newValue, breakPage);
ExecuteReplacement(nodesToReplace, matchIndex, matchEnd, newValue, splitValue);
return true;
}
internal static bool SimpleReplace(this Paragraph? paragraph, string oldValue, string newValue, StringComparison comparisonType, bool breakPage)
=> SimpleReplace(paragraph, oldValue, newValue, comparisonType, breakPage ? PageBreakType.PageBreak : PageBreakType.None);
internal static void Replace(this Paragraph paragraph, IEnumerable<KeyValuePair<string, string>> replacements, StringComparison comparisonType)
{
if (paragraph is null || replacements is null || replacements.Count() == 0)
@@ -120,10 +123,8 @@ internal static class SimplyReplaceExt
if (structure.FullText.Length == 0)
return;
// Используем List с предопределенной емкостью
var replacementsInParagraph = new List<ReplacementInfo>(replacements.Count() * 2);
// Сначала находим все вхождения
var fullText = structure.FullText;
foreach (var kvp in replacements)
{
@@ -137,7 +138,8 @@ internal static class SimplyReplaceExt
{
OldValue = kvp.Key,
NewValue = kvp.Value ?? string.Empty,
Index = pos
Index = pos,
SplitValue = PageBreakType.None
});
pos += kvp.Key.Length;
}
@@ -146,10 +148,8 @@ internal static class SimplyReplaceExt
if (replacementsInParagraph.Count == 0)
return;
// Сортируем по убыванию позиции
replacementsInParagraph.Sort((x, y) => y.Index.CompareTo(x.Index));
// Выполняем замены
for (int i = 0; i < replacementsInParagraph.Count; i++)
{
var replacement = replacementsInParagraph[i];
@@ -159,7 +159,7 @@ internal static class SimplyReplaceExt
var nodesToReplace = FindNodesToReplace(structure, matchIndex, matchEnd);
if (nodesToReplace.Count > 0)
{
ExecuteReplacement(nodesToReplace, matchIndex, matchEnd, replacement.NewValue);
ExecuteReplacement(nodesToReplace, matchIndex, matchEnd, replacement.NewValue, replacement.SplitValue);
}
}
}
@@ -177,10 +177,8 @@ internal static class SimplyReplaceExt
if (structure.FullText.Length == 0)
return;
// Используем List с предопределенной емкостью
var replacementsInParagraph = new List<ReplacementInfo>(replacements.Count() * 2);
// Сначала находим все вхождения
var fullText = structure.FullText;
foreach (var kvp in replacements)
{
@@ -194,8 +192,8 @@ internal static class SimplyReplaceExt
{
OldValue = kvp.Key,
NewValue = kvp.Value.Text ?? string.Empty,
BreakPage = kvp.Value.BreakPage,
Index = pos
Index = pos,
SplitValue = kvp.Value.SplitValue
});
pos += kvp.Key.Length;
}
@@ -204,10 +202,8 @@ internal static class SimplyReplaceExt
if (replacementsInParagraph.Count == 0)
return;
// Сортируем по убыванию позиции
replacementsInParagraph.Sort((x, y) => y.Index.CompareTo(x.Index));
// Выполняем замены
for (int i = 0; i < replacementsInParagraph.Count; i++)
{
var replacement = replacementsInParagraph[i];
@@ -217,7 +213,7 @@ internal static class SimplyReplaceExt
var nodesToReplace = FindNodesToReplace(structure, matchIndex, matchEnd);
if (nodesToReplace.Count > 0)
{
ExecuteReplacement(nodesToReplace, matchIndex, matchEnd, replacement.NewValue, replacement.BreakPage);
ExecuteReplacement(nodesToReplace, matchIndex, matchEnd, replacement.NewValue, replacement.SplitValue);
}
}
}
@@ -227,7 +223,7 @@ internal static class SimplyReplaceExt
internal string OldValue { get; set; } = null!;
internal string NewValue { get; set; } = null!;
internal int Index { get; set; }
internal bool BreakPage { get; set; }
internal PageBreakType SplitValue { get; set; } = PageBreakType.None;
}
private static ParagraphStructure AnalyzeParagraphStructure(IEnumerable<Run> runs)
@@ -287,11 +283,11 @@ internal static class SimplyReplaceExt
}
private static void ExecuteReplacement(
List<TextNodeInfo> nodesToReplace,
int matchStart,
int matchEnd,
string newValue,
bool breakPage = false)
List<TextNodeInfo> nodesToReplace,
int matchStart,
int matchEnd,
string newValue,
PageBreakType splitValue)
{
if (nodesToReplace.Count == 0) return;
@@ -311,22 +307,61 @@ internal static class SimplyReplaceExt
processedNewValue
);
// Очищаем остальные текстовые ноды
for (int i = 1; i < nodesToReplace.Count; i++)
{
nodesToReplace[i].Text.Text = string.Empty;
}
if (breakPage)
if (splitValue == PageBreakType.PageBreak)
{
if (nodesToReplace[0].Text.Parent is Run run && run.Parent is Paragraph para)
{
var breakRun = new Run(new Break() { Type = BreakValues.Page });
var breakRun = new Run(new Break { Type = BreakValues.Page });
if (run.RunProperties is not null)
breakRun.RunProperties = (RunProperties)run.RunProperties.CloneNode(true);
para.AppendChild(breakRun);
}
}
else if (splitValue == PageBreakType.NewLandscapeSection || splitValue == PageBreakType.NewPortraitSection)
{
var firstText = nodesToReplace[0].Text;
if (firstText.Parent is Run run && run.Parent is Paragraph para)
{
AddSectionProperties(para, splitValue);
}
}
}
private static void AddSectionProperties(Paragraph para, PageBreakType splitValue)
{
if (para is null) return;
PageOrientationValues orientation = splitValue == PageBreakType.NewLandscapeSection
? PageOrientationValues.Landscape
: PageOrientationValues.Portrait;
uint width, height;
if (orientation == PageOrientationValues.Landscape)
{
width = 16838;
height = 11906;
}
else
{
width = 11906;
height = 16838;
}
var sectionProps = new SectionProperties(
new PageSize
{
Width = width,
Height = height,
Orient = orientation
}
);
para.ParagraphProperties ??= new ParagraphProperties();
para.ParagraphProperties.AppendChild(sectionProps);
}
private static unsafe string ReplaceSpacesWithNonBreaking(string input)
@@ -358,7 +393,6 @@ internal static class SimplyReplaceExt
int end = Math.Min(start + length, original.Length);
// Оптимизированная конкатенация
var sb = new StringBuilder(original.Length - length + replacement.Length);
if (start > 0)
{