1.Quick start
2.Class overview
3.Static use
4.Performing replacements
5.Supported file types
6.Optimization
Table of Contents
1.Quick start
2.Class overview
3.Static use
4.Performing replacements
5.Supported file types
6.Optimization

Getting Started with the QuickReplace C# .NET Library

QuickReplace takes care of the difficult problem of automatically performing find and replaces in text, docx, and xlsx files, all with a single method call. It does this with speed, scalability, and ease of use in mind.

  • Perform find and replaces on multiple files with one method call, using any number of phrases either from a source file or in-memory dictionary.
  • Choose how the replacements should be made by controlling parameters such as Whole Word, Case Sensitive, and Preserve Case.
  • Style the replacements that were made in the output file by choosing between half a dozen style settings such as text color, highlight color, and bold text.
  • Code with performance in mind by utilizing QuickReplace's thread safety to maximize performance in your program or on your servers.

1. Quick Start

While there are many ways to customize your usage of the QuickReplace library, this section will cover the basics of installing and using the API.

1.1 Installing QuickReplace

To use the QuickReplace API in your .NET program, you must first import the package into your solution.

You can do this either by installing the package from the NuGet package manager or by downloading the dll directly.

To install the package with the NuGet Package Manager in Visual Studio,

  • Select Project > Manage NuGet Packages
  • In the top-right of the NuGet Package Manager page, choose nuget.org as the package source.
  • From the Browse tab, search for QuickReplace, select it, and then click Install.

You can also install the NuGet package from the console by navigating to:

  • Tools > NuGet Package Manager > Package Manager Console

And then entering the following into the console:

PM > Install-Package QuickReplace

1.2 Basic Usage

Note: This section will only cover the basic usage of the QuickReplace library. For more detailed information, please refer to the individual sections of each feature.

The simplest way to implement the QuickReplace API in your program is by performing three actions. First initialize your external data, then instantiate the QuickReplace class, and finally invoke the Replace method. Please see the following code snippet for an example of this usage:

Basic UsageC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = "replacementsFile.csv";
4.
var sources = new List<string> { "srcfile_1.txt", "srcfile_2.xlsx" };
5.
var outputs = new List<string> { "outfile_1.docx", "outfile_2.xlsx" };
6.
7.
// Instantiating QuickReplace class
8.
var qr = new QuickReplace(replacements, sources, outputs);
9.
10.
// Invoking the Replace method
11.
qr.Replace(wholeWord: true, caseSensitive: false, preserveCase: true);

In the above example, there are three pieces of external data that is needed to be gathered. First is the name of the file containing the replacement phrases. The QuickReplace constructor will parse the file and store the resulting data into a Dictionary named ReplacePhrases. If you do not need to read in the replacement phrases from an external file, you can alternatively pass in a Dictionary to the QuickReplace constructor directly.

The next two pieces of external data supplied are both lists of file names. One is a list of the source files that the find and replacements will be performed on, and the other is a list of the output file names that the resulting documents will be saved to. The QuickReplace constructor will zip these two lists together into one list called SourceFiles, which contains the source file names, output file names, and the number of replacements that are performed on each file.

After the external data is initialized, two more actions are performed. The external data is passed into the QuickReplace cosntructor, where it parses and stores the data into some fields. Finally, the Replace method is called, which performs the find and replacements on the given files. When calling this method, three flags must also be set to specify whether replacements should only be made on whole words, be case sensitive, or to preserve the case of the original word.

There are also two optional additional arguments you can pass to the Replace method which can disable exceptions from bubbling up and also set the styling of replacements made on docx and excel files:

Basic Usage Cont.C#
0.
using QuickReplace;
1.
using QuickReplace.DataTypes;
2.
3.
// Instantiating QuickReplace class
4.
var qr = new QuickReplace(replacements, sources, outputs);
5.
6.
// Creating the styling
7.
var styles = new Styling
8.
(
9.
	bold: true,
10.
	italics: true,
11.
	underline: true,
12.
	strikethrough: true,
13.
	highlightColor: "#FF0000",
14.
	textColor: "#FFFFFF",
15.
);
16.
17.
// Invoking the Replace method with custom styling
18.
qr.Replace(styling: styles, throwExceptions: false);

For more information about the specifics of these, you can read more about setting the replacements' styling or toggling the exception handling.

1.3 Static Usage

If it makes more sense for your implementation to use the API without having to manage QuickReplace objects, you can perform all of the functionality by using static methods. Below is a basic example of how this would be done:

Static UsageC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = QuickReplace.ParseReplacements("replacementsFile.csv");
4.
var sourceFiles = QuickReplace.ZipSourceFiles
5.
(
6.
	["srcfile_1.docx", "srcfile_2.xlsx"],
7.
	["outfile_1.docx", "outfile_2.xlsx"]
8.
);
9.
10.
// Invoking the Replace method
11.
QuickReplace.Replace(replacements, sourceFiles, wholeWord: true, caseSensitive: false, preserveCase: true);

To use QuickReplace statically, you must supply the data needed by the Replace method directly by invoking ParseReplacements on the file containing the replacement phrases, and by invoking ZipSourceFiles onto the list of source files and output files.

You can then invoke the Replace method statically by passing the data along with the normal arguments accepted by the non-static version of the Replace method.

1.4 Asynchronous Usage

Because efficiency with scale is the main priority of QuickReplace, the library is designed to be able to be completely thread-safe and even supports asyncronous operations out of the box. The Replace method can loop through the source filesasynchronously by specifying the numOfThreads argument:

Replace AsynchronouslyC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = "replacementsFile.csv";
4.
var sources = new List<string> { "srcfile_1.txt", "srcfile_2.xlsx" };
5.
var outputs = new List<string> { "outfile_1.docx", "outfile_2.xlsx" };
6.
7.
// Instantiating QuickReplace class
8.
var qr = new QuickReplace(replacements, sources, outputs);
9.
10.
// Invoke the Replace method asynchronously limited to two threads
11.
qr.Replace(numOfThreads: 2);
12.
13.
// Invoke the Replace method asynchronously with no thread limit
14.
qr.Replace(numOfThreads: 0);

As the above example shows, you can either limit the number of threads that will be used by passing an integer greater than 1, or you can leave it uncapped by passing an integer less than 1. There is also no need to invoke this method with an "await" keyword, as the Replace method will not return until all files have been processed.

For more information on how to implement the Replace method, please refer to the section on performing replacements.

2. QuickReplace Class Overview

All of the QuickReplace API's functionality can be accessed through the public methods of the QuickReplace class. Instantiating an object will perform the preprocessing automatically, however you are also provided static methods if you wish to use the library without having to create any class objects.

2.1 Constructor

The QuickReplace constructor is used to perform the preprocessing work automatically before the replacements are made. This includes instantiating data and optionally pre-generating the search algorithm's matcher automaton. More information about the data can be found in the Data Fields section.

Below is an example on how to instantiate the QuickReplace class:

Instantiating QuickReplaceC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = "replacements_file.csv";
4.
var sources = new List<string> { "source_file.docx" };
5.
var outputs = new List<string> { "output_file.docx" };
6.
7.
// Instantiating QuickReplace class
8.
var qr = new QuickReplace(replacements, sources, outputs);

In this example, the constructor is passed three things: the name of the file containing the replacement phrases, and two lists containing the names of the source files and the resulting output file names respectively.

Alternatively, you can pass the constructor the replacement phrases directly as a Dictionary instead of as an external file:

Instantiating QuickReplaceC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = new Dictionary<string, string>()
4.
{
5.
	{ "original", "replacement" },
6.
	{ "foo", "bar" }
7.
};
8.
9.
var sources = new List<string> { "source_file.docx" };
10.
var outputs = new List<string> { "output_file.docx" };
11.
12.
// Instantiating QuickReplace class
13.
var qr = new QuickReplace(replacements, sources, outputs);

Here instead of using the QuickReplace API to parse an external file containing the replace phrases, they are read in directly from memory instead. This saves a small amount processing time and memory, and may make more sense for your code implementation.

Additionally, the QuickReplace constructor can pre-generate the search algorithm's matcher automaton, which will frontload some of the processing onto the instantiation of the QuickReplace class rather than on the Replace method.

Note: The matcher is dependant on the replacement phrases rather than the source files. This means that if you pre-generate the matcher, it will need to be re-generated when the replacement phrases are changed, but not when new source files are used.

Below is an example of how to pre-generate the matcher with the QuickReplace constructor:

Pre-Generating MatcherC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = "replacements_file.csv";
4.
var sources = new List<string> { "source_file.docx" };
5.
var outputs = new List<string> { "output_file.docx" };
6.
7.
// Instantiating QuickReplace class
8.
var qr = new QuickReplace(replacements, sources, outputs, preGenerateMatcher: true, caseSensitive: true);

Here the pregenerateMatcher flag is set to true, which will cause the constructor to generate the matcher automaton. The caseSensitive flag must also be set, which dictates whether the search will be case sensitive or not.

2.2 Data Members

The QuickReplace class contains three data members that are of importance to the user of the API:

While they can all be set by instantiating the QuickReplace class, they have to be set manually when using static methods, which will be covered in the Manually Initializing Datasection.

2.2.1 ReplacePhrases

The ReplacePhrases data member is a Dictionary that contains the original and replacement terms as key-value pairs. This field can be changed at any time, and can be set directly like below:

Updating the ReplacePhrases MemberC#
0.
using QuickReplace;
1.
2.
// Instantiating QuickReplace class
3.
var qr = new QuickReplace(replacements, sources, outputs);
4.
5.
// Updating the ReplacePhrases data member from file name
6.
qr.ReplacePhrases = QuickReplace.ParseReplacements("replacements_filename");
7.
8.
// Updating the ReplacePhrases data member from dictionary
9.
qr.ReplacePhrases = new Dictionary<string, string>()
10.
{
11.
	{ "original", "replacement" },
12.
	{ "foo", "bar" }
13.
};

Here the ReplacePhrases data member is changed twice after being instantiated. The first time is by using the static method ParseReplacements, which takes in a filename as a string and returns a dictionary of original and replacement terms as key-value pairs. The second time the ReplacePhrases data member is changed is directly is by settings it equal to a Dictionary directly.

2.2.2 SourceFiles

Next, the SourceFiles data member is a List of objects of the SourceFile data type, which is a record usaed by the QuickReplace API. It contains three fields: SourceFileName, OutputFileName, and NumOfReplacements, which represent the names of a source file, the name of the output file after the replacements are performed, and the number of replacements that were performed on that file.

Here is an example on how the SourceFiles data member can be manually changed:

Updating the SourceFiles MemberC#
0.
using QuickReplace;
1.
2.
// Instantiating QuickReplace class
3.
var qr = new QuickReplace(replacements, sources, outputs);
4.
5.
// Preparing the new file names
6.
var sourceFileNames = new List<string> { "srcFile1", "srcFile2" };
7.
var outputFileNames = new List<string> { "outFile1", "outFile2" };
8.
9.
// Updating the SourceFiles data member
10.
qr.ReplacePhrases = QuickReplace.ZipSourceFiles(sourceFileNames, outputFileNames);

In the above example, the source and output file names are zipped together into the ReplacePhrases list, and all of their NumOfReplacements values are initialized to -1.

2.2.3 Matcher

Finally, the Matcher data member is a private object that is used internally by the QuickReplace API that is used by the search algorithm. While the Perform method will create a matcher automatically if one was not pre-generated, so it is not necessary to create one beforehand. However, it can improve performance if you are using the same set of replacements on multiple Replacement method calls. You can read more about this in the Optimization section.

Below is an example showing two ways to pre-generate the matcher:

Updating the Matcher MemberC#
0.
using QuickReplace;
1.
2.
// Instantiating QuickReplace class with a pre-generated matcher
3.
var qr = new QuickReplace(replacements, sources, outputs, preGenerateMatcher: true, caseSensitive: false);
4.
5.
// Manually generating the matcher
6.
qr.GenerateMatcher(caseSensitive: true);

First, the matcher is pre-generated by the QuickReplace constructor, which can be done optionally. Next, the matcher is generated again but with the case sensitive flag set to false.

Additionally, you can both remove the matcher and also check whether it exists:

Removing the Matcher MemberC#
0.
using QuickReplace;
1.
2.
// Instantiating QuickReplace class with a pre-generated matcher
3.
var qr = new QuickReplace(replacements, sources, outputs, preGenerateMatcher: true, caseSensitive: true);
4.
5.
qr.IsMatcherCreated(); // returns true
6.
7.
// Removing the matcher
8.
qr.ClearMatcher();
9.
10.
qr.IsMatcherCreated(); // returns false

2.3 Saving Replace Phrases to File

The QuickReplace library contains a SaveReplacePhrasesToFile method which allows you to save the replacement phrases to the file system. The supported file types are .xlsx, .csv, .tsv, and .txt. You can view how to do this statically in the static use section or from instance below:

Saving ReplacePhrases to FileC#
0.
using QuickReplace;
1.
2.
var qr = new QuickReplace(replacements, sources, outputs);
3.
4.
// Saving the ReplacePhirases data member to a file
5.
qp.SaveReplacePhrasesToFile("filename.csv");
6.
7.
// Sorting the phrases
8.
qp.SaveReplacePhrasesToFile("filename.csv", shouldSort: true);

If saving to a text file, this method will treat it as a "seperated value" file, and you can also optionally pass a delimiter to seperate the values. If a delimiter is not set, the SaveReplacePhrasesToFile method will default to using a comma:

Saving ReplacePhrases to Text FileC#
0.
using QuickReplace;
1.
2.
var qr = new QuickReplace(replacements, sources, outputs);
3.
4.
// Saving the ReplacePhirases data member to a text file
5.
qp.SaveReplacePhrasesToFile("filename.txt", delimiter: ";");
6.
7.
// Delimiter defaults to a comma
8.
qp.SaveReplacePhrasesToFile("filename.txt");

2.4 Replace Method

The Replace method is where the magic happens in the QuickReplace API. While this method will be covered more in detail in the Performing Replacements section, here is a basic example on how to invoke the Replace method:

Invoking the Replace MethodC#
0.
using QuickReplace;
1.
2.
// Instantiating QuickReplace class
3.
var qr = new QuickReplace(replacements, sources, outputs);
4.
5.
// Invoking the Replace method
6.
qr.Replace(wholeWord: true, caseSensitive: true, preserveCase: true);

In the above example, three replace optional flags are set, however they all default to false if omitted. There is also are additional flags for styling, one for ignoring exceptions, and another for invoking asynchronously. Additionally, the Replace method will automatically use the Matcher data member if one was pre-generated. If a matcher doesn't already exist, the Replace method will create a new matcher to use without assigning it to the Matcher data member.

3. Static Use

While most code examples have been done by instantiating an object of the QuickReplace class, you can actually achieve all of the functionality of the library with static methods.

3.1 Manually Initializing Data

Without instantiating the QuickReplace class, you will have to initialize data for the Replace method manually. Below is an example of how to initialize the replacement phrases and source files:

Initializing Data StaticallyC#
0.
using QuickReplace;
1.
2.
// Initialize the replacement phrases from a file name
3.
var replacements = QuickReplace.ParseReplacements("filename.csv");
4.
5.
// Initialize the replacement phrases from a Dictionary
6.
replacements = new Dictionary<string, string>()
7.
{
8.
	{ "original", "replacement" },
9.
	{ "foo", "bar" }
10.
};
11.
12.
// Initialize the source files
13.
var sourceFiles = QuickReplace.ZipSourceFiles(["srcFile.docx"], ["outputFile.docx"]);

3.2 Verifying Data

The QuickReplace class also has static methods to verify whether the files being used are valid. While the valid file types and type conversions are covered in the Supported File Types section, here is an example on how this is done:

Verifying DataC#
0.
using QuickReplace;
1.
2.
// returns true: .csv is valid for replacements file
3.
QuickReplace.IsReplacementFileTypeValid("filename.csv");
4.
5.
// returns false: .docx is invalid for replacements file
6.
QuickReplace.IsReplacementFileTypeValid("filename.docx");
7.
8.
// returns true: .txt to .docx conversion is valid
9.
QuickReplace.AreFilesValid("srcFile.txt", "outFile.docx");
10.
11.
// returns false: .xlsx to .docx conversion is invalid
12.
QuickReplace.AreFilesValid(
13.
	[ "srcFile1.txt, "srcFile2.xlsx" ],
14.
	[ "outFile1.txt, "outFile2.docx" ]
15.
);
16.
17.
var sourceFiles = QuickReplace.ZipSourceFiles(
18.
	[ "srcFile1.docx", "srcFile2.xlsx" ],
19.
	[ "outFile1.docx", "outFile2.xlsx" ]
20.
);
21.
22.
// returns true: file types are valid
23.
QuickReplace.AreFilesValid(sourceFiles);

You can view what file types are valid/invalid in the Supported File Types section.

Additionally, you can verify whether the source files are valid with the ZipSourceFiles method:

Verifying Source FilesC#
0.
using QuickReplace;
1.
2.
// Throws an InvalidFileTypeException
3.
var sourceFiles = QuickReplace.ZipSourceFiles(
4.
	[ "srcFile.docx", "invalid-file.bin" ],
5.
	[ "outFile.docx", "outFile.txt" ],
6.
	validateSrcFiles: true
7.
);

If one of the source files is not .docx, .xlsx, or a plaintext file, or if the corresponding output file is not of a supported file type conversion, the method will throw an InvalidFileTypeException.

3.3 Statically Saving Replace Phrases to File

If you are looking to write the dictionary of replacement phrases to a local file, the SaveReplacePhrasesToFile method allows you to do this. The supported file types are .xlsx, .csv, .tsv, and .txt. While you can also do this from a class instance , here is how to do this statically:

Statically Saving ReplacePhrases to FileC#
0.
using QuickReplace;
1.
2.
var replacements = QuickReplace.ParseReplacements("filename.csv");
3.
4.
// Statically saving the replacement phrases to a file
5.
QuickReplace.SaveReplacePhrasesToFile(replacements, "filename.csv");
6.
7.
// Sorting the phrases
8.
QuickReplace.SaveReplacePhrasesToFile(replacements, "filename.csv", shouldSort: true);

If saving to a text file, this method will treat it as a "seperated value" file, and you can also optionally pass a delimiter to seperate the values. If a delimiter is not set, the SaveReplacePhrasesToFile method will default to using a comma:

Statically Saving ReplacePhrases to Text FileC#
0.
using QuickReplace;
1.
2.
var replacements = QuickReplace.ParseReplacements("filename.csv");
3.
4.
// Statically saving the replacement phrases to a text file
5.
QuickReplace.SaveReplacePhrasesToFile(replacements, "filename.txt", delimiter: ";");
6.
7.
// Delimiter defaults to a comma
8.
qp.SaveReplacePhrasesToFile(replacements, "filename.txt");

3.4 Static Replace Method

The Replace method is where the magic happens in the QuickReplace API. While this method will be covered more in detail in the Performing Replacements section, here is a basic example on how to invoke the Replace method statically:

Replace Method StaticallyC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = QuickReplace.ParseReplacements("replacements.csv");
4.
var sourceFiles = QuickReplace.ZipSourceFiles(["source_file.docx"], ["output_file.docx"]);
5.
6.
// Invoking the Replace method
7.
QuickReplace.Replace(replacements, sourceFiles, wholeWord: true, caseSensitive: false, preserveCase: true);

In addition to the replacements and source files, the above example passes three optional flags: wholeWord, caseSensitive, and preserveCase. While this example sets them to true, they all default to false if omitted. There is also are additional flags for styling, one for ignoring exceptions, and another for invoking asynchronously.

4. Performing Replacements

The Replace method is where the QuickReplace library does its magic. It can be invoked either statically or from a QuickReplace object. It also has a number of different optional arguments that can be passed to the method. You can read more about what file types the Replace method can handle in the supported file types section.

4.1 From Instance vs. Statically

QuickReplace's Replace method an be invoked either from a class instance or statically. Both implementations are the same, hower the static version requires both the replacement phrases and the source files to be passed in as an argument. The code below shows how the Replace method is invoked from an instance:

Replace Method From InstanceC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = "replacements.csv";
4.
var sources = new List<string> { "source_file.docx" };
5.
var outputs = new List<string> { "output_file.docx" };
6.
7.
// Instantiating QuickReplace class
8.
var qr = new QuickReplace(replacements, sources, outputs);
9.
10.
// Invoking the Replace method
11.
qr.Replace(wholeWord: true, caseSensitive: false, preserveCase: true);

And here is an example of invoking the Replace method statically:

Replace Method StaticallyC#
0.
using QuickReplace;
1.
2.
// Initializing external data
3.
var replacements = QuickReplace.ParseReplacements("replacements.csv");
4.
var sourceFiles = QuickReplace.ZipSourceFiles(["source_file.docx"], ["output_file.docx"]);
5.
6.
// Invoking the Replace method
7.
QuickReplace.Replace(replacements, sourceFiles, wholeWord: true, caseSensitive: false, preserveCase: true);

Both examples above will complete the same exact operation, with only slight differences in implementation. The only advantage that one has over the other is that if the Replace method is invoked from an instance, you can pre-generate the search algorithm's matcher automaton, which will improve performance if the Replace method is called many times with the same replacement phrases.

Additionally, the Replace method allows for many file types to be passed to it, and will automatically convert vertain file types to other ones. More information about which file types are supported can be found in the supported file types section. If a file type or a file type conversion is not supported, the Replace method will throw a NotSupportedException.

4.2 Replacement Flags

The Replace method has a few optional flags that give some additional options in how the replacements should be made. Below is an example of invoking Replace with and without the flags:

Replacement FlagsC#
0.
using QuickReplace;
1.
2.
// Instantiating QuickReplace class
3.
var qr = new QuickReplace(replacements, sources, outputs);
4.
5.
// Invoking the Replace method with optional flags
6.
qr.Replace(wholeWord: true, caseSensitive: true, preserveCase: true);
7.
8.
// Invoking the Replace method with all flags set to false
9.
qr.Replace();

There are three flags that give additional options for how the Replae method performs replacements:

4.2.1 wholeWord

The wholeWord flag dictates whether the Replace method will only look for whole word matches.

4.2.2 caseSensitive

The caseSensitive flag dictates whether the Replace method will ignore capitalization.

Note: If the Replace method is being called by an object that pre-generated a matcher, this flag will be ignored and the Replace method will use the caseSensitive flag that was set when the matcher was created.

4.2.3 preserveCase

The preserveCase flag dictates whether the Replace method will force the replacement's capitalization to be the same as the original phrase. It checks to see if the original phrase is in all uppercase, all lowercase, first letter uppercase, or first letter lowercase, and will match the replacement to be the same.

4.3 Styling

The Replace method also allows you to customize the styling of the replacements that are made in the output file for .docx and .xlsx files. This is done by passing an object of the QuickReplace Styling class as an argument in the method:

Replace Method From InstanceC#
0.
using QuickReplace;
1.
using QuickReplace.DataTypes;
2.
3.
// Instantiating QuickReplace class
4.
var qr = new QuickReplace(replacements, sources, outputs);
5.
6.
// Creating the styling
7.
var styles = new Styling
8.
(
9.
	bold: true,
10.
	italics: true,
11.
	underline: true,
12.
	strikethrough: true,
13.
	highlightColor: "#FF0000",
14.
	textColor: "#FFFFFF",
15.
);
16.
17.
// Invoking the Replace method with custom styling
18.
qr.Replace(styling: styles);

4.3.1 Styling Class

The Styling class is used to tell the Replace method what styling should be applied to the replacements that were made on the output file. This class contains six fields:

  • bold
  • underline
  • highlightColor
  • italics
  • strikethrough
  • textColor

All of these fields are booleans, except for the highlightColor and textColor. These are both strings that represent a color in six-digit RGB hex form, either without a pound symbol.

You can also supply as many or few fields as needed. The Replace method will not apply the styling of a field that isn't set to true, and will only apply a highlight or text color if one is specified. If you would like to remove a color so that the Replace method does not apply it, simply pass an empty string into that field.

4.4 Exception Handling

The Replace method will also stop and throw an exception when something goes wrong. This means that if you pass in multiple files and an issue arises with one of them, it wont perform replacements on the following files. If you wish to instead continue normally with the other files, you can pass in the throwExceptions flag like so:

Disabling ExceptionsC#
0.
using QuickReplace;
1.
2.
// Instantiating QuickReplace class
3.
var qr = new QuickReplace(replacements, sources, outputs);
4.
5.
// Invoking the Replace method with exceptions disabled
6.
qr.Replace(throwExceptions: false);

Now instead of throwing an exception if an error occurred, the Replace method will continue processing all files and return false after everything is completed. If nothing goes wrong, it will return true.

There is however one exception that can still be thrown if throwExceptions is set to false. If the Replace method is being invoked statically and the list of SourceFiles is empty, it will throw an ArgumentException.

4.5 Replacement Edge Cases

When searching for multiple terms in the same operation like QuickReplace does, there can come times where multiple matches can overlap with eachother, or be "nested". For example, if you were have both "the" and "hereby" as phrases to search for:

Nested ReplacementsC#
0.
var replacements = new Dictionary<string, string>()
1.
{
2.
	{ "the", "foo" },
3.
	{ "hereby", "bar" }
4.
};

QuickReplace will handle this by favoring the one that starts first in the source text, and ignores the order of which comes first in the list of replacement phrases. So if the word "thereby" shows up in a source file, it will substitute the replacement phrase associated with "the":

thereby -> fooby

If two matches overlap eachother and also start at the same position, such as "add" and "addition":

Nested ReplacementsC#
0.
var replacements = new Dictionary<string, string>()
1.
{
2.
	{ "add", "foo" },
3.
	{ "additional", "bar" }
4.
};

Quickreplace handles this by favoring the phrase that is longer. So if the word "additionally" shows up in a source file, it will substitute the replacement phrase associated with "additional":

additionally -> barly

4.6 Invoking Asynchronously

In addition to QuickReplace being completely thread-safe, the library provides a way to invoke the Replace method asynchonously, and can loop through the source fileson multiple threads by specifying the numOfThreads argument:

Replace AsynchronouslyC#
0.
using QuickReplace;
1.
2.
var qr = new QuickReplace(replacements, sources, outputs);
3.
4.
// Invoke the Replace method asynchronously limited to two threads
5.
qr.Replace(numOfThreads: 2);
6.
7.
// Invoke the Replace method asynchronously with no thread limit
8.
qr.Replace(numOfThreads: 0);

As the above example shows, you can either limit the number of threads that will be used by passing an integer greater than 1, or you can leave it uncapped by passing an integer less than 1. There is also no need to invoke this method with an "await" keyword, as the Replace method will not return until all files have been processed.

This can be done both from an instance of the QuickReplace class or statically as well.

5. Supported File Types

In short, the QuickReplace library supports document (.docx), excel (.xlsx), and all types of text files. For the external file that is parsed to get the replacement phrases , csv/tsv or excel files are recommended, however text files can also be used. Additionally, QuickReplace does not support legacy document or excel files (.doc and .xls).

QuickReplace determines what a text file is by checking whether the first few thousand bytes of a file contains a null character. While UTF-8 text files will pass this requirement, UTF-16 and binary files will fail.

5.1 Input/Output Files

Any text file, .docx file, or .xlsx file can be used as a source or output file for the Replace method. Additionally, a document input file can be converted to a text output file, as well as a text input file can be converted to a document output file and even have styling applied to it. However, excel input files cannot be converted to another file type, and other file types cannot be converted to an excel file. If an invalid file type or file type conversion is supplied to the Replace method, it will throw a NotSupportedException.

If an output file name has any extension other than .docx or .xlsx, it will be treated as a plaintext file, regardless of extension.

5.2 Replacement Phrases File

For the external file that is parsed to get the replacement phrases , csv/tsv or excel files are recommended, however text files can also be used. For text files, QuickReplace will treat it as a "seperated value" file attempt to parse it.

If an Excel file is used, the first two columns must contain the original and replacement phrases respectively. Any other columns will be ignored.

When saving the replacement phrases to a file, the supported file types are identical, however an explicit delimiter must be provided for text files.

6. Optimization

The QuickReplace library has been designed with speed as the #1 priority. The ability to be more efficient at a larger scale is invaluable when processing files, especially on a server. This is why QuickReplace supports two main methods to improve performance more and more as your program scales up.

6.1 Pre-Generating Matcher

If the same replacement phrases will be used over multiple invocations of the Replace method, it will save time and processing power to pre-generate the search algorithm's matcher automaton.

QuickReplace uses the Aho-Corasick algorithm to find the matches within each file. There are two main advantages to using this search algorithm. Firstly, it is designed to be able to lbe most efficient when searching large files, which is perfect when you don't always know the size of the files that are being processed. Additionally, the Aho-Corasick algorithm works by doing some pre-processing and creating an automaton for the terms that are being searched for. This makes it optimal for searching for many different terms through many different files with the same automaton, meaning that it again becomes more efficient at scale.

If this feature is something you'd like to implement in your code, you must invoke the Replace method from an object of the QuickReplace constructor rather than invoking it statically. For more information on how to do this, please see the section on the Matcher data member.

6.2 Multi-Threading

Because efficiency with scale is the main priority of QuickReplace, the library is designed to be able to be used completely asynchronously and even supports asyncronous operations out of the box. The Replace method can loop through the source filesasynchronously by specifying the numOfThreads argument:

Replace AsynchronouslyC#
0.
using QuickReplace;
1.
2.
var qr = new QuickReplace(replacements, sources, outputs);
3.
4.
// Invoke the Replace method asynchronously limited to two threads
5.
qr.Replace(numOfThreads: 2);
6.
7.
// Invoke the Replace method asynchronously with no thread limit
8.
qr.Replace(numOfThreads: 0);

As the above example shows, you can either limit the number of threads that will be used by passing an integer greater than 1, or you can leave it uncapped by passing an integer less than 1. There is also no need to invoke this method with an "await" keyword, as the Replace method will not return until all files have been processed.

For more information on how to implement the Replace method, please refer to the section on performing replacements.

© 2024 QuickReplace, LLC. All Rights Reserved.