https://docx.codeplex.com/workitem/13827 - to preserve Formatting during replace operations https://docx.codeplex.com/workitem/13831 - proper RegEx support allowing RegEx search pattern and substitutions in ReplaceTextmaster
| @@ -422,7 +422,7 @@ namespace Novacode | |||
| return uniqueResults.Keys.ToList(); // return the unique list of results | |||
| } | |||
| public virtual void ReplaceText(string searchValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch) | |||
| public virtual void ReplaceText(string searchValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false) | |||
| { | |||
| if (string.IsNullOrEmpty(searchValue)) | |||
| throw new ArgumentException("oldValue cannot be null or empty", "searchValue"); | |||
| @@ -434,18 +434,18 @@ namespace Novacode | |||
| foreach (var header in headerList) | |||
| if (header != null) | |||
| foreach (var paragraph in header.Paragraphs) | |||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions); | |||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions); | |||
| // ReplaceText int main body of document. | |||
| foreach (var paragraph in Paragraphs) | |||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions); | |||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions); | |||
| // ReplaceText in Footers of the document. | |||
| var footerList = new List<Footer> { Document.Footers.first, Document.Footers.even, Document.Footers.odd }; | |||
| foreach (var footer in footerList) | |||
| if (footer != null) | |||
| foreach (var paragraph in footer.Paragraphs) | |||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions); | |||
| paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions); | |||
| } | |||
| /// <summary> | |||
| @@ -10,38 +10,38 @@ namespace Novacode | |||
| /// </summary> | |||
| public class Formatting : IComparable | |||
| { | |||
| private XElement rPr; | |||
| private bool hidden; | |||
| private bool bold; | |||
| private bool italic; | |||
| private StrikeThrough strikethrough; | |||
| private Script script; | |||
| private Highlight highlight; | |||
| private double? size; | |||
| private Color? fontColor; | |||
| private Color? underlineColor; | |||
| private UnderlineStyle underlineStyle; | |||
| private Misc misc; | |||
| private CapsStyle capsStyle; | |||
| private FontFamily fontFamily; | |||
| private int? percentageScale; | |||
| private int? kerning; | |||
| private int? position; | |||
| private double? spacing; | |||
| private CultureInfo language; | |||
| private XElement rPr; | |||
| private bool? hidden; | |||
| private bool? bold; | |||
| private bool? italic; | |||
| private StrikeThrough? strikethrough; | |||
| private Script? script; | |||
| private Highlight? highlight; | |||
| private double? size; | |||
| private Color? fontColor; | |||
| private Color? underlineColor; | |||
| private UnderlineStyle? underlineStyle; | |||
| private Misc? misc; | |||
| private CapsStyle? capsStyle; | |||
| private FontFamily fontFamily; | |||
| private int? percentageScale; | |||
| private int? kerning; | |||
| private int? position; | |||
| private double? spacing; | |||
| private CultureInfo language; | |||
| /// <summary> | |||
| /// A text formatting. | |||
| /// </summary> | |||
| public Formatting() | |||
| { | |||
| capsStyle = CapsStyle.none; | |||
| strikethrough = StrikeThrough.none; | |||
| script = Script.none; | |||
| highlight = Highlight.none; | |||
| underlineStyle = UnderlineStyle.none; | |||
| misc = Misc.none; | |||
| capsStyle = Novacode.CapsStyle.none; | |||
| strikethrough = Novacode.StrikeThrough.none; | |||
| script = Novacode.Script.none; | |||
| highlight = Novacode.Highlight.none; | |||
| underlineStyle = Novacode.UnderlineStyle.none; | |||
| misc = Novacode.Misc.none; | |||
| // Use current culture by default | |||
| language = CultureInfo.CurrentCulture; | |||
| @@ -65,7 +65,35 @@ namespace Novacode | |||
| } | |||
| } | |||
| public static Formatting Parse(XElement rPr) | |||
| /// <summary> | |||
| /// Returns a new identical instance of Formatting. | |||
| /// </summary> | |||
| /// <returns></returns> | |||
| public Formatting Clone() | |||
| { | |||
| Formatting newf = new Formatting(); | |||
| newf.Bold = bold; | |||
| newf.CapsStyle = capsStyle; | |||
| newf.FontColor = fontColor; | |||
| newf.FontFamily = fontFamily; | |||
| newf.Hidden = hidden; | |||
| newf.Highlight = highlight; | |||
| newf.Italic = italic; | |||
| if (kerning.HasValue) { newf.Kerning = kerning; } | |||
| newf.Language = language; | |||
| newf.Misc = misc; | |||
| if (percentageScale.HasValue) { newf.PercentageScale = percentageScale; } | |||
| if (position.HasValue) { newf.Position = position; } | |||
| newf.Script = script; | |||
| if (size.HasValue) { newf.Size = size; } | |||
| if (spacing.HasValue) { newf.Spacing = spacing; } | |||
| newf.StrikeThrough = strikethrough; | |||
| newf.UnderlineColor = underlineColor; | |||
| newf.UnderlineStyle = underlineStyle; | |||
| return newf; | |||
| } | |||
| public static Formatting Parse(XElement rPr) | |||
| { | |||
| Formatting formatting = new Formatting(); | |||
| @@ -167,67 +195,76 @@ namespace Novacode | |||
| ); | |||
| } | |||
| if(hidden) | |||
| rPr.Add(new XElement(XName.Get("vanish", DocX.w.NamespaceName))); | |||
| if (bold) | |||
| rPr.Add(new XElement(XName.Get("b", DocX.w.NamespaceName))); | |||
| if (italic) | |||
| rPr.Add(new XElement(XName.Get("i", DocX.w.NamespaceName))); | |||
| switch (underlineStyle) | |||
| { | |||
| case UnderlineStyle.none: | |||
| break; | |||
| case UnderlineStyle.singleLine: | |||
| rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "single"))); | |||
| break; | |||
| case UnderlineStyle.doubleLine: | |||
| rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "double"))); | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), underlineStyle.ToString()))); | |||
| break; | |||
| } | |||
| if (hidden.HasValue && hidden.Value) | |||
| rPr.Add(new XElement(XName.Get("vanish", DocX.w.NamespaceName))); | |||
| if (bold.HasValue && bold.Value) | |||
| rPr.Add(new XElement(XName.Get("b", DocX.w.NamespaceName))); | |||
| if (italic.HasValue && italic.Value) | |||
| rPr.Add(new XElement(XName.Get("i", DocX.w.NamespaceName))); | |||
| if (underlineStyle.HasValue) | |||
| { | |||
| switch (underlineStyle) | |||
| { | |||
| case Novacode.UnderlineStyle.none: | |||
| break; | |||
| case Novacode.UnderlineStyle.singleLine: | |||
| rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "single"))); | |||
| break; | |||
| case Novacode.UnderlineStyle.doubleLine: | |||
| rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "double"))); | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), underlineStyle.ToString()))); | |||
| break; | |||
| } | |||
| } | |||
| if(underlineColor.HasValue) | |||
| { | |||
| // If an underlineColor has been set but no underlineStyle has been set | |||
| if (underlineStyle == UnderlineStyle.none) | |||
| if (underlineStyle == Novacode.UnderlineStyle.none) | |||
| { | |||
| // Set the underlineStyle to the default | |||
| underlineStyle = UnderlineStyle.singleLine; | |||
| underlineStyle = Novacode.UnderlineStyle.singleLine; | |||
| rPr.Add(new XElement(XName.Get("u", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), "single"))); | |||
| } | |||
| rPr.Element(XName.Get("u", DocX.w.NamespaceName)).Add(new XAttribute(XName.Get("color", DocX.w.NamespaceName), underlineColor.Value.ToHex())); | |||
| } | |||
| switch (strikethrough) | |||
| { | |||
| case StrikeThrough.none: | |||
| break; | |||
| case StrikeThrough.strike: | |||
| rPr.Add(new XElement(XName.Get("strike", DocX.w.NamespaceName))); | |||
| break; | |||
| case StrikeThrough.doubleStrike: | |||
| rPr.Add(new XElement(XName.Get("dstrike", DocX.w.NamespaceName))); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| switch (script) | |||
| { | |||
| case Script.none: | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get("vertAlign", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), script.ToString()))); | |||
| break; | |||
| } | |||
| if (size.HasValue) | |||
| if (strikethrough.HasValue) | |||
| { | |||
| switch (strikethrough) | |||
| { | |||
| case Novacode.StrikeThrough.none: | |||
| break; | |||
| case Novacode.StrikeThrough.strike: | |||
| rPr.Add(new XElement(XName.Get("strike", DocX.w.NamespaceName))); | |||
| break; | |||
| case Novacode.StrikeThrough.doubleStrike: | |||
| rPr.Add(new XElement(XName.Get("dstrike", DocX.w.NamespaceName))); | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| } | |||
| if (script.HasValue) | |||
| { | |||
| switch (script) | |||
| { | |||
| case Novacode.Script.none: | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get("vertAlign", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), script.ToString()))); | |||
| break; | |||
| } | |||
| } | |||
| if (size.HasValue) | |||
| { | |||
| rPr.Add(new XElement(XName.Get("sz", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), (size * 2).ToString()))); | |||
| rPr.Add(new XElement(XName.Get("szCs", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), (size * 2).ToString()))); | |||
| @@ -236,63 +273,72 @@ namespace Novacode | |||
| if(fontColor.HasValue) | |||
| rPr.Add(new XElement(XName.Get("color", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), fontColor.Value.ToHex()))); | |||
| switch (highlight) | |||
| { | |||
| case Highlight.none: | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get("highlight", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), highlight.ToString()))); | |||
| break; | |||
| } | |||
| switch (capsStyle) | |||
| { | |||
| case CapsStyle.none: | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get(capsStyle.ToString(), DocX.w.NamespaceName))); | |||
| break; | |||
| } | |||
| switch (misc) | |||
| { | |||
| case Misc.none: | |||
| break; | |||
| case Misc.outlineShadow: | |||
| rPr.Add(new XElement(XName.Get("outline", DocX.w.NamespaceName))); | |||
| rPr.Add(new XElement(XName.Get("shadow", DocX.w.NamespaceName))); | |||
| break; | |||
| case Misc.engrave: | |||
| rPr.Add(new XElement(XName.Get("imprint", DocX.w.NamespaceName))); | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get(misc.ToString(), DocX.w.NamespaceName))); | |||
| break; | |||
| } | |||
| return rPr; | |||
| if (highlight.HasValue) | |||
| { | |||
| switch (highlight) | |||
| { | |||
| case Novacode.Highlight.none: | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get("highlight", DocX.w.NamespaceName), new XAttribute(XName.Get("val", DocX.w.NamespaceName), highlight.ToString()))); | |||
| break; | |||
| } | |||
| } | |||
| if (capsStyle.HasValue) | |||
| { | |||
| switch (capsStyle) | |||
| { | |||
| case Novacode.CapsStyle.none: | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get(capsStyle.ToString(), DocX.w.NamespaceName))); | |||
| break; | |||
| } | |||
| } | |||
| if (misc.HasValue) | |||
| { | |||
| switch (misc) | |||
| { | |||
| case Novacode.Misc.none: | |||
| break; | |||
| case Novacode.Misc.outlineShadow: | |||
| rPr.Add(new XElement(XName.Get("outline", DocX.w.NamespaceName))); | |||
| rPr.Add(new XElement(XName.Get("shadow", DocX.w.NamespaceName))); | |||
| break; | |||
| case Novacode.Misc.engrave: | |||
| rPr.Add(new XElement(XName.Get("imprint", DocX.w.NamespaceName))); | |||
| break; | |||
| default: | |||
| rPr.Add(new XElement(XName.Get(misc.ToString(), DocX.w.NamespaceName))); | |||
| break; | |||
| } | |||
| } | |||
| return rPr; | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// This formatting will apply Bold. | |||
| /// </summary> | |||
| public bool Bold { get { return bold; } set { bold = value;} } | |||
| public bool? Bold { get { return bold; } set { bold = value;} } | |||
| /// <summary> | |||
| /// This formatting will apply Italic. | |||
| /// </summary> | |||
| public bool Italic { get { return italic; } set { italic = value; } } | |||
| public bool? Italic { get { return italic; } set { italic = value; } } | |||
| /// <summary> | |||
| /// This formatting will apply StrickThrough. | |||
| /// </summary> | |||
| public StrikeThrough StrikeThrough { get { return strikethrough; } set { strikethrough = value; } } | |||
| public StrikeThrough? StrikeThrough { get { return strikethrough; } set { strikethrough = value; } } | |||
| /// <summary> | |||
| /// The script that this formatting should be, normal, superscript or subscript. | |||
| /// </summary> | |||
| public Script Script { get { return script; } set { script = value; } } | |||
| public Script? Script { get { return script; } set { script = value; } } | |||
| /// <summary> | |||
| /// The Size of this text, must be between 0 and 1638. | |||
| @@ -398,12 +444,12 @@ namespace Novacode | |||
| /// <summary> | |||
| /// Highlight colour. | |||
| /// </summary> | |||
| public Highlight Highlight { get { return highlight; } set { highlight = value; } } | |||
| public Highlight? Highlight { get { return highlight; } set { highlight = value; } } | |||
| /// <summary> | |||
| /// The Underline style that this formatting applies. | |||
| /// </summary> | |||
| public UnderlineStyle UnderlineStyle { get { return underlineStyle; } set { underlineStyle = value; } } | |||
| public UnderlineStyle? UnderlineStyle { get { return underlineStyle; } set { underlineStyle = value; } } | |||
| /// <summary> | |||
| /// The underline colour. | |||
| @@ -413,20 +459,20 @@ namespace Novacode | |||
| /// <summary> | |||
| /// Misc settings. | |||
| /// </summary> | |||
| public Misc Misc { get { return misc; } set { misc = value; } } | |||
| public Misc? Misc { get { return misc; } set { misc = value; } } | |||
| /// <summary> | |||
| /// Is this text hidden or visible. | |||
| /// </summary> | |||
| public bool Hidden { get { return hidden; } set { hidden = value; } } | |||
| public bool? Hidden { get { return hidden; } set { hidden = value; } } | |||
| /// <summary> | |||
| /// Capitalization style. | |||
| /// </summary> | |||
| public CapsStyle CapsStyle { get { return capsStyle; } set { capsStyle = value; } } | |||
| public CapsStyle? CapsStyle { get { return capsStyle; } set { capsStyle = value; } } | |||
| /// <summary> | |||
| /// The font familt of this formatting. | |||
| /// The font family of this formatting. | |||
| /// </summary> | |||
| /// <!-- | |||
| /// Bug found and fixed by krugs525 on August 12 2009. | |||
| @@ -2002,26 +2002,66 @@ namespace Novacode | |||
| // Get the first run effected by this Insert | |||
| Run run = GetFirstRunEffectedByEdit(index); | |||
| if (run == null) | |||
| { | |||
| object insert; | |||
| if (formatting != null) | |||
| insert = HelperFunctions.FormatInput(value, formatting.Xml); | |||
| else | |||
| insert = HelperFunctions.FormatInput(value, null); | |||
| if (trackChanges) | |||
| insert = CreateEdit(EditType.ins, insert_datetime, insert); | |||
| Xml.Add(insert); | |||
| } | |||
| else | |||
| { | |||
| object newRuns; | |||
| if (formatting != null) | |||
| newRuns = HelperFunctions.FormatInput(value, formatting.Xml); | |||
| else | |||
| newRuns = HelperFunctions.FormatInput(value, run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName))); | |||
| if (run == null) | |||
| { | |||
| object insert; | |||
| if (formatting != null) //not sure how to get original formatting here when run == null | |||
| insert = HelperFunctions.FormatInput(value, formatting.Xml); | |||
| else | |||
| insert = HelperFunctions.FormatInput(value, null); | |||
| if (trackChanges) | |||
| insert = CreateEdit(EditType.ins, insert_datetime, insert); | |||
| Xml.Add(insert); | |||
| } | |||
| else | |||
| { | |||
| object newRuns; | |||
| var rprel = run.Xml.Element(XName.Get("rPr", DocX.w.NamespaceName)); | |||
| if (formatting != null) | |||
| { | |||
| //merge 2 formattings properly | |||
| Formatting finfmt = null; | |||
| Formatting oldfmt = null; | |||
| if (rprel != null) | |||
| { | |||
| oldfmt = Formatting.Parse(rprel); | |||
| } | |||
| if (oldfmt != null) | |||
| { | |||
| finfmt = oldfmt.Clone(); | |||
| if (formatting.Bold.HasValue) { finfmt.Bold = formatting.Bold; } | |||
| if (formatting.CapsStyle.HasValue) { finfmt.CapsStyle = formatting.CapsStyle; } | |||
| if (formatting.FontColor.HasValue) { finfmt.FontColor = formatting.FontColor; } | |||
| finfmt.FontFamily = formatting.FontFamily; | |||
| if (formatting.Hidden.HasValue) { finfmt.Hidden = formatting.Hidden; } | |||
| if (formatting.Highlight.HasValue) { finfmt.Highlight = formatting.Highlight; } | |||
| if (formatting.Italic.HasValue) { finfmt.Italic = formatting.Italic; } | |||
| if (formatting.Kerning.HasValue) { finfmt.Kerning = formatting.Kerning; } | |||
| finfmt.Language = formatting.Language; | |||
| if (formatting.Misc.HasValue) { finfmt.Misc = formatting.Misc; } | |||
| if (formatting.PercentageScale.HasValue) { finfmt.PercentageScale = formatting.PercentageScale; } | |||
| if (formatting.Position.HasValue) { finfmt.Position = formatting.Position; } | |||
| if (formatting.Script.HasValue) { finfmt.Script = formatting.Script; } | |||
| if (formatting.Size.HasValue) { finfmt.Size = formatting.Size; } | |||
| if (formatting.Spacing.HasValue) { finfmt.Spacing = formatting.Spacing; } | |||
| if (formatting.StrikeThrough.HasValue) { finfmt.StrikeThrough = formatting.StrikeThrough; } | |||
| if (formatting.UnderlineColor.HasValue) { finfmt.UnderlineColor = formatting.UnderlineColor; } | |||
| if (formatting.UnderlineStyle.HasValue) { finfmt.UnderlineStyle = formatting.UnderlineStyle; } | |||
| } | |||
| else { | |||
| finfmt = formatting; | |||
| } | |||
| newRuns = HelperFunctions.FormatInput(value, finfmt.Xml); | |||
| } | |||
| else | |||
| { | |||
| newRuns = HelperFunctions.FormatInput(value, rprel); | |||
| } | |||
| // The parent of this Run | |||
| XElement parentElement = run.Xml.Parent; | |||
| @@ -3751,59 +3791,62 @@ namespace Novacode | |||
| RemoveText(index, Text.Length - index, trackChanges); | |||
| } | |||
| /// <summary> | |||
| /// Replaces all occurrences of a specified System.String in this instance, with another specified System.String. | |||
| /// </summary> | |||
| /// <example> | |||
| /// <code> | |||
| /// // Load a document using a relative filename. | |||
| /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) | |||
| /// { | |||
| /// // The formatting to match. | |||
| /// Formatting matchFormatting = new Formatting(); | |||
| /// matchFormatting.Size = 10; | |||
| /// matchFormatting.Italic = true; | |||
| /// matchFormatting.FontFamily = new FontFamily("Times New Roman"); | |||
| /// | |||
| /// // The formatting to apply to the inserted text. | |||
| /// Formatting newFormatting = new Formatting(); | |||
| /// newFormatting.Size = 22; | |||
| /// newFormatting.UnderlineStyle = UnderlineStyle.dotted; | |||
| /// newFormatting.Bold = true; | |||
| /// | |||
| /// // Iterate through the paragraphs in this document. | |||
| /// foreach (Paragraph p in document.Paragraphs) | |||
| /// { | |||
| /// /* | |||
| /// * Replace all instances of the string "wrong" with the string "right" and ignore case. | |||
| /// * Each inserted instance of "wrong" should use the Formatting newFormatting. | |||
| /// * Only replace an instance of "wrong" if it is Size 10, Italic and Times New Roman. | |||
| /// * SubsetMatch means that the formatting must contain all elements of the match formatting, | |||
| /// * but it can also contain additional formatting for example Color, UnderlineStyle, etc. | |||
| /// * ExactMatch means it must not contain additional formatting. | |||
| /// */ | |||
| /// p.ReplaceText("wrong", "right", false, RegexOptions.IgnoreCase, newFormatting, matchFormatting, MatchFormattingOptions.SubsetMatch); | |||
| /// } | |||
| /// | |||
| /// // Save all changes made to this document. | |||
| /// document.Save(); | |||
| /// }// Release this document from memory. | |||
| /// </code> | |||
| /// </example> | |||
| /// <seealso cref="Paragraph.RemoveText(int, int, bool)"/> | |||
| /// <seealso cref="Paragraph.RemoveText(int, bool)"/> | |||
| /// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/> | |||
| /// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/> | |||
| /// <param name="newValue">A System.String to replace all occurances of oldValue.</param> | |||
| /// <param name="oldValue">A System.String to be replaced.</param> | |||
| /// <param name="options">A bitwise OR combination of RegexOption enumeration options.</param> | |||
| /// <param name="trackChanges">Track changes</param> | |||
| /// <param name="newFormatting">The formatting to apply to the text being inserted.</param> | |||
| /// <param name="matchFormatting">The formatting that the text must match in order to be replaced.</param> | |||
| /// <param name="fo">How should formatting be matched?</param> | |||
| public void ReplaceText(string oldValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch) | |||
| /// <summary> | |||
| /// Replaces all occurrences of a specified System.String in this instance, with another specified System.String. | |||
| /// </summary> | |||
| /// <example> | |||
| /// <code> | |||
| /// // Load a document using a relative filename. | |||
| /// using (DocX document = DocX.Load(@"C:\Example\Test.docx")) | |||
| /// { | |||
| /// // The formatting to match. | |||
| /// Formatting matchFormatting = new Formatting(); | |||
| /// matchFormatting.Size = 10; | |||
| /// matchFormatting.Italic = true; | |||
| /// matchFormatting.FontFamily = new FontFamily("Times New Roman"); | |||
| /// | |||
| /// // The formatting to apply to the inserted text. | |||
| /// Formatting newFormatting = new Formatting(); | |||
| /// newFormatting.Size = 22; | |||
| /// newFormatting.UnderlineStyle = UnderlineStyle.dotted; | |||
| /// newFormatting.Bold = true; | |||
| /// | |||
| /// // Iterate through the paragraphs in this document. | |||
| /// foreach (Paragraph p in document.Paragraphs) | |||
| /// { | |||
| /// /* | |||
| /// * Replace all instances of the string "wrong" with the string "right" and ignore case. | |||
| /// * Each inserted instance of "wrong" should use the Formatting newFormatting. | |||
| /// * Only replace an instance of "wrong" if it is Size 10, Italic and Times New Roman. | |||
| /// * SubsetMatch means that the formatting must contain all elements of the match formatting, | |||
| /// * but it can also contain additional formatting for example Color, UnderlineStyle, etc. | |||
| /// * ExactMatch means it must not contain additional formatting. | |||
| /// */ | |||
| /// p.ReplaceText("wrong", "right", false, RegexOptions.IgnoreCase, newFormatting, matchFormatting, MatchFormattingOptions.SubsetMatch); | |||
| /// } | |||
| /// | |||
| /// // Save all changes made to this document. | |||
| /// document.Save(); | |||
| /// }// Release this document from memory. | |||
| /// </code> | |||
| /// </example> | |||
| /// <seealso cref="Paragraph.RemoveText(int, int, bool)"/> | |||
| /// <seealso cref="Paragraph.RemoveText(int, bool)"/> | |||
| /// <seealso cref="Paragraph.InsertText(int, string, bool, Formatting)"/> | |||
| /// <seealso cref="Paragraph.InsertText(string, bool, Formatting)"/> | |||
| /// <param name="newValue">A System.String to replace all occurrences of oldValue.</param> | |||
| /// <param name="oldValue">A System.String to be replaced.</param> | |||
| /// <param name="options">A bitwise OR combination of RegexOption enumeration options.</param> | |||
| /// <param name="trackChanges">Track changes</param> | |||
| /// <param name="newFormatting">The formatting to apply to the text being inserted.</param> | |||
| /// <param name="matchFormatting">The formatting that the text must match in order to be replaced.</param> | |||
| /// <param name="fo">How should formatting be matched?</param> | |||
| /// <param name="escapeRegEx">True if the oldValue needs to be escaped, otherwise false. If it represents a valid RegEx pattern this should be false.</param> | |||
| /// <param name="useRegExSubstitutions">True if RegEx-like replace should be performed, i.e. if newValue contains RegEx substitutions. Does not perform named-group substitutions (only numbered groups).</param> | |||
| public void ReplaceText(string oldValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false) | |||
| { | |||
| MatchCollection mc = Regex.Matches(Text, Regex.Escape(oldValue), options); | |||
| string tText = Text; | |||
| MatchCollection mc = Regex.Matches(tText, escapeRegEx ? Regex.Escape(oldValue) : oldValue, options); | |||
| // Loop through the matches in reverse order | |||
| foreach (Match m in mc.Cast<Match>().Reverse()) | |||
| @@ -3847,7 +3890,38 @@ namespace Novacode | |||
| // If the formatting matches, do the replace. | |||
| if (formattingMatch) | |||
| { | |||
| InsertText(m.Index + oldValue.Length, newValue, trackChanges, newFormatting); | |||
| string repl = newValue; | |||
| //perform RegEx substitutions. Only named groups are not supported. Everything else is supported. However character escapes are not covered. | |||
| if (useRegExSubstitutions) | |||
| { | |||
| repl = repl.Replace("$&", m.Value); | |||
| if (m.Groups.Count > 0) | |||
| { | |||
| int lastcap = 0; | |||
| for (int k = 0; k < m.Groups.Count; k++) | |||
| { | |||
| var g = m.Groups[k]; | |||
| if ((g == null) || (g.Value == "")) | |||
| continue; | |||
| repl = repl.Replace("$" + k.ToString(), g.Value); | |||
| lastcap = k; | |||
| //cannot get named groups ATM | |||
| } | |||
| repl = repl.Replace("$+", m.Groups[lastcap].Value); | |||
| } | |||
| if (m.Index > 0) | |||
| { | |||
| repl = repl.Replace("$`", tText.Substring(0, m.Index)); | |||
| } | |||
| if ((m.Index + m.Length) < tText.Length) | |||
| { | |||
| repl = repl.Replace("$'", tText.Substring(m.Index + m.Length)); | |||
| } | |||
| repl = repl.Replace("$_", tText); | |||
| repl = repl.Replace("$$", "$"); | |||
| } | |||
| InsertText(m.Index + m.Length, repl, trackChanges, newFormatting); | |||
| RemoveText(m.Index, m.Length, trackChanges); | |||
| } | |||
| } | |||