8.5. Text Operations#

This section covers the core string operations needed before and during text parsing: cleaning, splitting, searching, replacing, and reading structured records.

8.5.1. Text Basics#

Before parsing text, clean it first.

string raw = "   Alice,  93  ";

string trimmed = raw.Trim();                      // "Alice,  93"
string upper   = trimmed.ToUpper();               // "ALICE,  93"
string lower   = trimmed.ToLower();               // "alice,  93"
bool   empty   = string.IsNullOrWhiteSpace(raw);  // false

Console.WriteLine($"trimmed: '{trimmed}'");
Console.WriteLine($"upper:   '{upper}'");
Console.WriteLine($"lower:   '{lower}'");
Console.WriteLine($"empty:   {empty}");

Use these rules:

  • Call Trim() before splitting fields

  • Call IsNullOrWhiteSpace() before parsing

  • Normalize case when comparisons should be case-insensitive

8.5.2. Accessing Characters#

string s = "cat";

for (int i = 0; i < s.Length; i++)
{
    Console.WriteLine($"{i}: {s[i]}");
}

// Never index a string unless bounds are known to be valid.

8.5.3. String Immutability#

Strings are immutable in C#. All string methods return new strings; the original is unchanged.

string a = "hello";
string b = a.ToUpper();  // b = "HELLO", a is still "hello"

Console.WriteLine($"a = {a}");
Console.WriteLine($"b = {b}");

8.5.4. Splitting and Tokenizing#

Splitting turns one text line into meaningful fields.

string line    = "Ada,98,CS";
string[] parts = line.Split(',');

Console.WriteLine(parts[0]);  // Ada
Console.WriteLine(parts[1]);  // 98
Console.WriteLine(parts[2]);  // CS

Input often has extra whitespace — trim each field after splitting:

string line = " Ada , 98 , CS ";
string[] parts = line.Split(',');

for (int i = 0; i < parts.Length; i++)
    parts[i] = parts[i].Trim();

foreach (var p in parts)
    Console.WriteLine($"'{p}'");

When input may contain repeated delimiters, remove empty entries:

string line = "Ada,,CS";
string[] parts = line.Split(',', StringSplitOptions.RemoveEmptyEntries);

Console.WriteLine(parts.Length);  // 2

8.5.4.1. Token Validation#

Validate the number of fields before accessing by index:

string line = "Ada,98,CS";
string[] parts = line.Split(',');

if (parts.Length != 3)
{
    Console.WriteLine("Invalid record: expected 3 fields.");
}
else
{
    Console.WriteLine($"Name: {parts[0].Trim()}, Score: {parts[1].Trim()}, Major: {parts[2].Trim()}");
}

8.5.5. Search and Replace#

Search and replace is useful for cleanup and normalization pipelines.

string message = "error: invalid input";

bool hasError = message.Contains("error",  StringComparison.OrdinalIgnoreCase);
int  at       = message.IndexOf("invalid", StringComparison.OrdinalIgnoreCase);

Console.WriteLine($"hasError: {hasError}");
Console.WriteLine($"'invalid' starts at index: {at}");

Use StringComparison.OrdinalIgnoreCase for consistent case-insensitive checks.

string raw     = "Name: Alice\tScore: 98";
string cleaned = raw.Replace("\t", " ");

Console.WriteLine(cleaned);

8.5.5.1. Safe Replacement Strategy#

  1. Preserve the original text

  2. Create a cleaned copy

  3. Validate the output

  4. Write to a new file first

string original = "Score: N/A";
string updated  = original.Replace("N/A", "0");

Console.WriteLine($"original: {original}");
Console.WriteLine($"updated:  {updated}");

8.5.6. Structured Lines#

Structured lines are text records with predictable field order.

Example record: Alice,98,CS

Field model:

  1. name (string)

  2. score (int)

  3. major (string)

static bool TryParseStudent(string line, out string name, out int score, out string major)
{
    name  = "";
    major = "";
    score = 0;

    if (string.IsNullOrWhiteSpace(line)) return false;

    string[] parts = line.Split(',');
    if (parts.Length != 3) return false;

    name  = parts[0].Trim();
    major = parts[2].Trim();

    return int.TryParse(parts[1].Trim(), out score);
}
string[] records = { "Alice,98,CS", "Bob,abc,Math", "Carol,87,Physics", "" };

foreach (string line in records)
{
    if (TryParseStudent(line, out string name, out int score, out string major))
        Console.WriteLine($"{name} ({major}) scored {score}");
    else
        Console.WriteLine($"Skipped malformed line: '{line}'");
}

Footnotes