{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "name": "csharp"
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "# Regular Expressions\n\nRegular expressions (regex) are patterns that describe text. They extend the string search and replace operations from the previous section, letting you match flexible, structured patterns instead of exact strings.\n\n> Regex lives in the `System.Text.RegularExpressions` namespace.",
   "id": "c3921bb0"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": "using System.Text.RegularExpressions;",
   "id": "bfaec7ea"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Checking for a Match\n\n`Regex.IsMatch` returns `true` if the pattern appears anywhere in the string:",
   "id": "ac51b659"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using System.Text.RegularExpressions;\n",
    "\n",
    "// Does the string contain any digit?\n",
    "bool hasDigit = Regex.IsMatch(\"Score: 98\", @\"\\d\");\n",
    "Console.WriteLine(hasDigit);  // True\n",
    "\n",
    "// Does it start with a capital letter?\n",
    "bool startsUpper = Regex.IsMatch(\"Alice\", @\"^[A-Z]\");\n",
    "Console.WriteLine(startsUpper);  // True"
   ],
   "id": "eebea810"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Common Pattern Elements\n\n| Pattern | Meaning | Example match |\n|---------|---------|---------------|\n| `\\d` | any digit | `7`, `0` |\n| `\\w` | word character (letter, digit, `_`) | `a`, `Z`, `3` |\n| `\\s` | whitespace | space, tab |\n| `.` | any character except newline | `x`, `!` |\n| `^` | start of string | `^Hello` matches `Hello world` |\n| `$` | end of string | `\\.txt$` matches `file.txt` |\n| `[abc]` | one of a, b, c | `[aeiou]` matches any vowel |\n| `[A-Z]` | range | any uppercase letter |\n| `+` | one or more | `\\d+` matches `42` |\n| `*` | zero or more | `\\d*` matches `` or `99` |\n| `?` | zero or one | `colou?r` matches `color` or `colour` |",
   "id": "119d0865"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Extracting a Match\n\n`Regex.Match` returns the first match object:",
   "id": "2abcccf3"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using System.Text.RegularExpressions;\n",
    "\n",
    "string line = \"Student: Alice, Score: 98\";\n",
    "Match m = Regex.Match(line, @\"\\d+\");\n",
    "\n",
    "if (m.Success)\n",
    "    Console.WriteLine($\"First number found: {m.Value}\");  // 98"
   ],
   "id": "38c4e0cd"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Finding All Matches\n\n`Regex.Matches` returns every match:",
   "id": "07e353d3"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using System.Text.RegularExpressions;\n",
    "\n",
    "string data = \"Scores: 85, 92, 78, 90\";\n",
    "MatchCollection matches = Regex.Matches(data, @\"\\d+\");\n",
    "\n",
    "foreach (Match m in matches)\n",
    "    Console.WriteLine(m.Value);\n",
    "// 85  92  78  90"
   ],
   "id": "e548c0b6"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Replacing with a Pattern\n\n`Regex.Replace` substitutes every match:",
   "id": "6671644e"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using System.Text.RegularExpressions;\n",
    "\n",
    "// Normalize multiple spaces to one\n",
    "string messy = \"Alice,  98,   CS\";\n",
    "string clean = Regex.Replace(messy, @\"\\s{2,}\", \" \");\n",
    "Console.WriteLine(clean);  // Alice,  98,   CS -> \"Alice, 98, CS\""
   ],
   "id": "2937a394"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using System.Text.RegularExpressions;\n",
    "\n",
    "// Remove all non-digit characters\n",
    "string phone = \"(312) 555-0190\";\n",
    "string digits = Regex.Replace(phone, @\"[^\\d]\", \"\");\n",
    "Console.WriteLine(digits);  // 3125550190"
   ],
   "id": "80c26c68"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Using Groups to Extract Fields\n\nParentheses create **capture groups** — named parts of a match:",
   "id": "46bf9c48"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using System.Text.RegularExpressions;\n",
    "\n",
    "string record = \"Alice,98,CS\";\n",
    "Match m = Regex.Match(record, @\"^(?<name>\\w+),(?<score>\\d+),(?<major>\\w+)$\");\n",
    "\n",
    "if (m.Success)\n",
    "{\n",
    "    Console.WriteLine($\"Name:  {m.Groups[\"name\"].Value}\");\n",
    "    Console.WriteLine($\"Score: {m.Groups[\"score\"].Value}\");\n",
    "    Console.WriteLine($\"Major: {m.Groups[\"major\"].Value}\");\n",
    "}"
   ],
   "id": "d06ac1ef"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Validation Patterns\n\nCommon tasks well-suited to regex:",
   "id": "310a1a97"
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "using System.Text.RegularExpressions;\n",
    "\n",
    "// Simple email check (not exhaustive)\n",
    "bool isEmail = Regex.IsMatch(\"user@example.com\", @\"^[\\w.+-]+@[\\w-]+\\.[a-z]{2,}$\");\n",
    "Console.WriteLine($\"valid email: {isEmail}\");\n",
    "\n",
    "// Zip code (5 digits)\n",
    "bool isZip = Regex.IsMatch(\"60660\", @\"^\\d{5}$\");\n",
    "Console.WriteLine($\"valid zip: {isZip}\");\n",
    "\n",
    "// Date format YYYY-MM-DD\n",
    "bool isDate = Regex.IsMatch(\"2026-03-17\", @\"^\\d{4}-\\d{2}-\\d{2}$\");\n",
    "Console.WriteLine($\"valid date: {isDate}\");"
   ],
   "id": "ce80efc3"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## When to Use Regex vs. String Methods\n\n| Use `string` methods | Use regex |\n|---------------------|-----------|\n| Exact match or replace | Pattern-based match |\n| Fixed delimiter `Split(',')` | Variable whitespace or delimiters |\n| `Contains`, `StartsWith` | Character classes, repetition |\n| Performance-critical loops | One-time validation or extraction |\n\nRegex adds power but also complexity — prefer `Split`, `Trim`, and `Contains` when the pattern is simple and fixed.",
   "id": "3b6d3c49"
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": "## Practice\n\n1. Write a pattern to match a C# `int` or `double` literal (e.g. `42`, `-3`, `3.14`).\n2. Extract all words (sequences of `\\w+`) from a sentence and print each on its own line.\n3. Validate that a filename ends with `.cs` or `.txt`.\n4. Replace all tab characters in a file line with four spaces.",
   "id": "c2ceba6e"
  },
  {
   "cell_type": "markdown",
   "id": "footnotes",
   "metadata": {},
   "source": "```{rubric} Footnotes\n```\n"
  }
 ]
}
