---
title: "Compare two strings word by word in C#"
url: https://recursiveai.org/onediff/cookbook/compare-text/
description: "Compare two strings in C# at word level, render inline Markdown, inspect edit runs, and choose whether case changes count. Includes a runnable example."
version: "1.0.1"
---

# Compare two strings word by word in C#

**OneDiff** is a free, open-source diff library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneDiff) · [GitHub](https://github.com/recursive-ai-oss/onediff-csharp) · [Docs](https://recursiveai.org/onediff/docs/) · [Download example (.zip)](https://recursiveai.org/onediff/cookbook/compare-text/compare-text.zip)

Find added and removed words in two strings.

```shell
dotnet add package RecursiveAI.OneDiff
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using OneDiff;

var diff = Diff.Words(
    "Pay within 30 days.",
    "Pay within 60 days.");
Console.WriteLine(
    Diff.ToMarkdownInline(diff));
```

```text
Pay within <del>30</del><ins>60</ins> days.
```

Unzip [the example](https://recursiveai.org/onediff/cookbook/compare-text/compare-text.zip), then `dotnet run`.

## The full program

The inputs are the two strings shown here; no files or document adapters are needed. The full program also lists the edit runs. Null text arguments throw `ArgumentNullException`.

```csharp
using OneDiff;

string oldText = "Pay within 30 days.";
string newText = "Pay within 60 days.";
var diff = Diff.Words(oldText, newText);
Console.WriteLine(Diff.ToMarkdownInline(diff));
foreach (var piece in diff.Pieces)
    Console.WriteLine($"{piece.Kind}: [{piece.Text}]");
```

`dotnet run` prints:

```text
Pay within <del>30</del><ins>60</ins> days.
Equal: [Pay within ]
Delete: [30]
Insert: [60]
Equal: [ days.]
```

## Variations

**Ignore case, but not other changes.** This is a complete replacement program:

```csharp
using OneDiff;
using OneDiff.Tokenization;

var diff = Diff.WordsUsing(
    "Pay now", "PAY now", TokenComparer.IgnoreCase);
Console.WriteLine(
    Diff.ToMarkdownInline(diff));
```

```text
PAY now
```

**Compare characters instead of words.**

```csharp
using OneDiff;

var diff = Diff.Characters("cat", "cut");
Console.WriteLine(
    Diff.ToMarkdownInline(diff));
```

```text
c<del>a</del><ins>u</ins>t
```

## Related recipes

- [Apply a unified diff patch](https://recursiveai.org/onediff/cookbook/apply-unified-patch/)
- [Write a side-by-side HTML diff](https://recursiveai.org/onediff/cookbook/side-by-side-html-diff/)

## The short answer

Use `Diff.Words(oldText, newText)` to get a word-level `TextDiff`, then pass it to `Diff.ToMarkdownInline` for a marked-up string. Deleted text is inside `<del>` and inserted text inside `<ins>`. In the example, only the payment period changes: `30` is removed and `60` is inserted. The core package is sufficient; this does not read Word or PDF documents.

## How do I compare two strings and get the difference in C#?

An equality test answers whether two strings match under a chosen rule. A diff answers where they differ and carries the old and new content. Here, the return value is a `TextDiff`, not a Boolean or a string ordering result.

For a human-readable result, render inline Markdown as in the snippet at the top. For application logic, walk `diff.Pieces` as the full program does. Each run has a `Kind`: `Equal`, `Delete` or `Insert`. Its `Text` is the run’s content. `OldLine` and `NewLine` are one-based source line numbers; an insertion has no old line and a deletion has no new line. These are line positions, not character offsets. Keep the brackets in the sample’s output while debugging so spaces remain visible.

One replacement can therefore appear as a deletion followed by an insertion rather than a single “replace” object. Don’t count those runs as two independent business changes unless that is what your application intends. Word-level text edits say what changed in the string, not what the change means in a contract.

The core’s tokenizer treats a whitespace run as a token, keeps an apostrophe between letters within a word, and keeps a decimal separator between digits within a number. It is script-aware but is not Unicode UAX #29 word segmentation. For details and the original API rules, see the [text output documentation](https://recursiveai.org/onediff/docs/text-output/) and [public tokenizer source](https://github.com/recursive-ai-oss/onediff-csharp/blob/6443915c4136cc8c5a49fa2543322011665f309e/src/OneDiff/Tokenization/WordTokenizer.cs).

## How do I compare strings ignoring case in C#?

Use `Diff.WordsUsing` with `TokenComparer.IgnoreCase`, as in the variation. The default word diff does not silently ignore case. The comparer changes what counts as equal while the result still refers to the original tokens. The case-insensitive example renders the new text, `PAY now`, without insertion or deletion tags; it does not lowercase your source string.

Keep normalization explicit. If case matters to a reviewer, use the default comparison. If your application deliberately treats capitalization as irrelevant, choose the comparer and document that decision next to the code. Separate whitespace comparers are available; ignoring case does not automatically ignore spaces, punctuation or all other typography. The [comparer API source](https://github.com/recursive-ai-oss/onediff-csharp/blob/6443915c4136cc8c5a49fa2543322011665f309e/src/OneDiff/Diff.Comparers.cs) lists the supported choices.

The inline renderer escapes ampersands and less-than signs, but leaves other Markdown as written. That makes it useful in a Markdown workflow, not a general-purpose HTML sanitization step. Render it with the content policy appropriate to your application, or use the dedicated HTML report recipe for a standalone comparison page.
