# C#正則表達式:強大的文本匹配工具
{%hackmd BJrTq20hE %}
<style>
.markdown-body:not(.next-editor) pre {
padding: 16px;
background-color: #333;
}
.markdown-body pre.flow-chart, .markdown-body pre.sequence-diagram, .markdown-body pre.graphviz, .markdown-body pre.mermaid, .markdown-body pre.abc {
background-color: #d9edf7 !important;<!-mermaidbg-!>
}
.markdown-body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
padding-top: 40px;
padding-bottom: 40px;
max-width: 800px; <!-筆記寬度-!>
overflow: visible !important;
position: relative;
}
</style>
在C#開發中,處理文本是一項常見的任務。無論是搜索文本、驗證輸入、提取信息還是進行文本轉換,都需要一種有效的工具來處理文本。這就是C#正則表達式的優越之處。
### 什麼是正則表達式?
正則表達式(Regular Expressions),簡稱正則或Regex,是一種強大的文本處理工具,它允許根據特定模式匹配和操作字符串。它不僅限於C#,而是通用的文本處理工具,被廣泛應用於各種程式語言和應用中。
### 命名空間和引用
首先,為了使用正則表達式,需要引入 `System.Text.RegularExpressions` 命名空間。可以在C#代碼中這樣做:
```csharp!
using System.Text.RegularExpressions;
```
### 常用方法和函數
#### 1\. `Regex.IsMatch` 方法(常用於驗證的方式)
`Regex.IsMatch` 方法用於檢查字符串是否匹配正則表達式模式。它的基本用法如下:
```csharp!
string input = "your_input_string";
string pattern = @"your_regex_pattern";
bool isMatch = Regex.IsMatch(input, pattern);
```
`isMatch` 變數將包含布林值,指示是否有匹配。
範例:
```csharp!
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string input = "The quick brown fox jumps over the lazy dog.";
string pattern = @"\bfox\b"; // 正則表達式模式,匹配單獨的 "fox"
bool isMatch = Regex.IsMatch(input, pattern);
if (isMatch)
{
Console.WriteLine("The input contains the word 'fox'.");
}
else
{
Console.WriteLine("The input does not contain the word 'fox'.");
}
}
}
```
#### 2\. `Regex.Match` 方法(用於調用匹配的值、索引、長度)
`Regex.Match` 方法用於在字符串中尋找第一個匹配項,並返回一個 `Match` 對象,其中包含有關匹配的信息。以下是一個示例:
```csharp!
string input = "your_input_string";
string pattern = @"your_regex_pattern";
Match match = Regex.Match(input, pattern);
```
可以使用 `match` 對象來訪問有關匹配的詳細信息,例如匹配的值、位置等。
`Match` 對象包含有關單個匹配的信息,例如匹配的值、位置等。可以通過以下方式訪問這些信息:
```csharp!
Match match = Regex.Match(input, pattern);
if (match.Success)
{
string value = match.Value; // 匹配的值
int startIndex = match.Index; // 匹配的起始索引
int length = match.Length; // 匹配的長度
}
```
範例:
```csharp!
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string input = "The price of the product is $99.99, and the discount is 20%.";
string pattern = @"\$\d+\.\d{2}"; // 正則表達式模式,匹配價格
// 在輸入字符串中尋找第一個匹配
Match match = Regex.Match(input, pattern);
// 檢查是否有匹配
if (match.Success)
{
string value = match.Value; // 匹配的值,即 "$99.99"
int startIndex = match.Index; // 匹配的起始索引,即 23
int length = match.Length; // 匹配的長度,即 7
Console.WriteLine("Original String: " + input);
Console.WriteLine("Matched Value: " + value);
Console.WriteLine("Start Index: " + startIndex);
Console.WriteLine("Length: " + length);
}
else
{
Console.WriteLine("No match found.");
}
}
}
```
在這個例子中,我們有一個包含價格信息的字符串 `input`,我們使用正則表達式 `pattern` 來匹配第一個價格。然後,我們創建了一個 `Match` 對象 `match`,它包含有關匹配的信息。我們檢查 `match.Success`,以確保找到了匹配。
如果有匹配,我們可以使用 `match.Value` 獲取匹配的值(即 `$99.99`)、`match.Index` 獲取匹配的起始索引(即 23)、以及 `match.Length` 獲取匹配的長度(即 7)。
#### 3\. `Regex.Matches` 方法
`Regex.Matches` 方法用於在字符串中查找所有匹配項,並返回一個 `MatchCollection` 對象,其中包含多個 `Match` 對象。以下是一個示例:
```csharp!
string input = "your_input_string_with_multiple_matches";
string pattern = @"your_regex_pattern";
MatchCollection matches = Regex.Matches(input, pattern);
```
`matches` 對象包含了所有匹配的信息,可以遍歷它以獲取每個匹配的詳細信息。
#### 4\. `Regex.Replace` 方法
`Regex.Replace` 方法用於替換字符串中的匹配項。它的基本用法如下:
```csharp!
string input = "your_input_string_with_matches_to_replace";
string pattern = @"your_regex_pattern";
string replacement = "replacement_text";
string result = Regex.Replace(input, pattern, replacement);
```
`result` 變數將包含替換後的新字符串。
範例:
```csharp!
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
string input = "Hello, my email is user123@example.com, and my friend's email is friend456@example.com";
string pattern = @"\b\w+@\w+\.\w+\b"; // 正則表達式模式,匹配電子郵件地址
// 替換所有的電子郵件地址為 "[email hidden]"
string replacement = "[email hidden]";
string result = Regex.Replace(input, pattern, replacement);
Console.WriteLine("Original String: " + input);
Console.WriteLine("Modified String: " + result);
}
}
```
在這個例子中,我們有一個包含電子郵件地址的字符串 `input`。我們使用正則表達式 `pattern` 來匹配所有的電子郵件地址。然後,我們將匹配到的電子郵件地址都替換為 `[email hidden]`,並將結果存儲在 `result` 變數中。
這些方法和函數是使用C#正則表達式時最常用的。它們可以幫助執行各種文本處理任務,包括驗證、提取和替換。
### 簡單的正則表達式示例
讓我們看一個簡單的正則表達式示例。假設我們想要驗證一個字符串是否是合法的電子郵件地址。以下是一個用於此目的的簡單正則表達式:
```csharp
string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$";
```
**解釋**:
- `^` 和 `$`:這些符號分別表示字符串的開頭和結尾。在上面的示例中,它們用於確保整個字符串匹配模式。
- `[]`:方括號用於定義字符集。例如,`[a-zA-Z]` 匹配任何一個小寫或大寫字母。
- `+` 和 `*`:`+` 表示匹配前面的模式一次或多次,而 `*` 表示匹配零次或多次。
- `.`:匹配除換行符之外的任何字符。
- `\`:用於轉義特殊字符。例如,`\.` 匹配句點字符而不是通配符。
- `{}`:用於指定匹配次數的範圍。例如,`{2,4}` 表示匹配2到4次。
所以,這個正則表達式用來確保輸入字符串具有一般的電子郵件格式,例如`example@email.com`。
### 正則表達式的基本元素
正則表達式包含一些基本元素,讓我們更深入地了解它們:
1. `^` 和 `$`:這些是錨定字符,分別表示字符串的開頭和結尾。
2. `[]`:方括號用於定義字符集。例如,`[a-zA-Z]` 匹配任何一個小寫或大寫字母。
3. `+` 和 `*`:`+` 表示匹配前面的模式一次或多次,而 `*` 表示匹配零次或多次。
4. `.`:匹配除換行符之外的任何字符。
5. `\`:用於轉義特殊字符。例如,`\.` 匹配句點字符而不是通配符。
6. `{}`:用於指定匹配次數的範圍。例如,`{2,4}` 表示匹配2到4次。
### 使用正則表達式的示例
現在,讓我們深入解釋每個示例的工作原理:
#### 1\. **驗證電話號碼**:
```csharp!
string phoneNumberPattern = @"^\d{3}-\d{3}-\d{4}$";
bool isValid = Regex.IsMatch(input, phoneNumberPattern);
```
**解釋**:
- `^\d{3}-\d{3}-\d{4}$` 正則表達式用於驗證美國標準的電話號碼,例如`123-456-7890`。
- `^\d{3}`:開頭必須是三個數字。
- `-`:接著是一個短橫線。
- `\d{3}`:然後是另外三個數字。
- `-`:再次是一個短橫線。
- `\d{4}`:最後是四個數字。
- `$`:最後必須是字符串的結尾。
只有當輸入字符串完全符合`123-456-7890`的格式時,`isValid`變量才會為`true`。
#### 2\. **提取URL中的域名**:(用括號來產生匹配組,並提取特定內容)
```csharp!
string url = "https://www.example.com";
string domainPattern = @"^https?://(www\.)?([a-zA-Z0-9.-]+)";
Match match = Regex.Match(url, domainPattern);
string domain = match.Groups[2].Value;
```
**解釋**:
- `^https?://(www\.)?([a-zA-Z0-9.-]+)` 正則表達式用於提取URL中的域名。
- `^https?://`:匹配URL的開頭,可以是`http://`或`https://`。
- `(www\.)?`:匹配可選的`www.`子域。
- `([a-zA-Z0-9.-]+)`:匹配域名部分,可以包含字母、數字、句點和短橫線
- `
Match match = Regex.Match(url, domainPattern);`:這一行代碼使用正則表達式 `domainPattern` 在 `url` 字符串中尋找匹配。如果找到了匹配,它將存儲在 `match` 變數中。
- `string domain = match.Groups[2].Value;`:這一行代碼從 `match` 中提取第二個匹配組(由圓括號 `()` 括起來的部分),這部分代表域名。提取的域名存儲在 `domain` 變數中。
所以,如果 `url` 字符串是 `https://www.example.com`,`domain` 變數將包含 `example.com`,這是提取的域名部分。
#### 3\. **替換文本中的HTML標記**:
```csharp!
string html = "<p>Hello, <strong>world</strong>!</p>";
string noHtml = Regex.Replace(html, "<.*?>", "");
```
**解釋**:
- `<.*?>` 正則表達式用於匹配HTML標記,包括標記的開始和結束部分。
- `<` 和 `>`:這些字符匹配左尖括號和右尖括號,它們是HTML標記的標誌。
- `.*`:這部分匹配任何字符(`.`)零次或多次(`*`),這允許匹配標記之間的內容。
- `?`:這個字符表示匹配模式是非貪婪的,這意味著它會匹配最短的字符串,以便在遇到第一個結束標記時停止。
所以,使用 `Regex.Replace` 方法,我們可以將 `html` 字符串中的所有HTML標記替換為空字符串,從而得到不包含標記的純文本字符串,即 `"Hello, world!"`。
這些示例展示了C#正則表達式的基本用法,可以根據需求應用不同的正則表達式來執行文本匹配、驗證、提取和轉換操作。
## 常用元素
| 元素 | 解釋 |
| --- | --- |
| `.` | 匹配任何一個字符,除了換行符(像是 Enter 鍵)。 |
| `*` | 匹配前一個字符零次或多次。例如,`a*` 可以匹配零個或多個字母 "a"。 |
| `+` | 匹配前一個字符一次或多次。例如,`b+` 可以匹配一個或多個字母 "b"。 |
| `?` | 匹配前一個字符零次或一次,表示它是可選的。例如,`colou?r` 可以匹配 "color" 和 "colour"。 |
| `[]` | 用於定義一組字符,匹配這組字符中的任何一個。例如,`[aeiou]` 可以匹配任何一個元音字母。 |
| `[^]` | 在 `[]` 內使用插入符號 `^`,表示匹配不在這組字符中的任何一個字符。例如,`[^0-9]` 可以匹配任何非數字字符。 |
| `()` | 用於創建一個組,可以捕獲這個組匹配到的內容,以後可以使用。 |
| `|` | 表示或操作,匹配左側或右側的內容。例如,`cat|dog` 可以匹配 "cat" 或 "dog"。 |
| `\d` | 匹配任何數字字符,等同於 `[0-9]`。 |
| `\D` | 匹配任何非數字字符,等同於 `[^0-9]`。 |
| `\w` | 匹配任何字母、數字或底線字符,等同於 `[a-zA-Z0-9_]`。 |
| `\W` | 匹配任何非字母、非數字或非底線字符,等同於 `[^a-zA-Z0-9_]`。 |
| `\s` | 匹配任何空白字符,包括空格、制表符和換行符。 |
| `\S` | 匹配任何非空白字符。 |
| `^` | 匹配輸入字符串的開頭。 |
| `$` | 匹配輸入字符串的結尾。 |
| `\b` | 匹配單詞的邊界,通常用於單詞的全字匹配。 |
| `\B` | 匹配非單詞的邊界。 |
Reference:
菜鳥教程:
https://www.runoob.com/regexp/regexp-metachar.html
微軟官方:
https://learn.microsoft.com/zh-tw/dotnet/api/system.text.regularexpressions.regex?view=net-7.0