65、编程中的正则表达式、XPath及格式化方法详解

编程中的正则表达式、XPath及格式化方法详解

1. 正则表达式参考

正则表达式在大多数文本解析和文本匹配任务中扮演着重要角色,它是 -split -match 运算符、 switch 语句、 Select-String cmdlet 等的重要基础。以下是常用正则表达式的详细介绍。

1.1 字符类

字符类用于表示一组字符的模式,常见的字符类及其匹配规则如下表所示:
| 字符类 | 匹配规则 | 示例 |
| — | — | — |
| . | 除换行符外的任意字符。若正则表达式使用 SingleLine 选项,则匹配任意字符。 | PS > "T" -match '.' 结果为 True |
| [characters] | 方括号内的任意字符。例如 [aeiou] 。 | PS > "Test" -match '[Tes]' 结果为 True |
| [^characters] | 不在方括号内的任意字符。例如 [^aeiou] 。 | PS > "Test" -match '[^Tes]' 结果为 False |
| [start-end] | start end 之间的任意字符(包含 start end )。方括号内可包含多个字符范围。例如 [a-eh-j] 。 | PS > "Test" -match '[e-t]' 结果为 True |
| [^start-end] | 不在任何 start end 字符范围内的任意字符(包含 start end )。方括号内可包含多个字符范围。例如 [^a-eh-j] 。 | PS > "Test" -match '[^e-t]' 结果为 False |
| \p{character class} | {character class} 指定的 Unicode 组或块范围内的任意字符。 | PS > "+" -match '\p{Sm}' 结果为 True |
| \P{character class} | 不在 {character class} 指定的 Unicode 组或块范围内的任意字符。 | PS > "+" -match '\P{Sm}' 结果为 False |
| \w | 任意单词字符。这是 Unicode 定义的单词字符,包括数字、许多数学符号和其他各种符号。 | PS > "a" -match '\w' 结果为 True |
| \W | 任意非单词字符。 | PS > "!" -match '\W' 结果为 True |
| \s | 任意空白字符。 | PS > " t” -match ‘\s’ 结果为 True | | \S | 任意非空白字符。 | PS > ” t" -match '\S' 结果为 False |
| \d | 任意十进制数字。 | PS > "5" -match '\d' 结果为 True |
| \D | 任意非十进制数字的字符。 | PS > "!" -match '\D' 结果为 True |

1.2 量词

量词用于对前面的表达式进行数量限制,常见的量词及其含义如下表所示:
| 量词 | 含义 | 示例 |
| — | — | — |
| <none> | 一次匹配。 | PS > "T" -match 'T' 结果为 True |
| * | 零次或多次匹配,尽可能多地匹配。 | PS > "A" -match 'T*' 结果为 True PS > "TTTTT" -match '^T*$' 结果为 True PS > 'ATTT' -match 'AT*'; $Matches[0] 结果为 True ,匹配结果为 ATTT |
| + | 一次或多次匹配,尽可能多地匹配。 | PS > "A" -match 'T+' 结果为 False PS > "TTTTT" -match '^T+$' 结果为 True PS > 'ATTT' -match 'AT+'; $Matches[0] 结果为 True ,匹配结果为 ATTT |
| ? | 零次或一次匹配,尽可能多地匹配。 | PS > "TTTTT" -match '^T?$' 结果为 False PS > 'ATTT' -match 'AT?'; $Matches[0] 结果为 True ,匹配结果为 AT |
| {n} | 恰好 n 次匹配。 | PS > "TTTTT" -match '^T{5}$' 结果为 True |
| {n,} | n 次或更多次匹配,尽可能多地匹配。 | PS > "TTTTT" -match '^T{4,}$' 结果为 True |
| {n,m} | n m 次匹配(包含 n m ),尽可能多地匹配。 | PS > "TTTTT" -match '^T{4,6}$' 结果为 True |
| *? | 零次或多次匹配,尽可能少地匹配。 | PS > "A" -match '^AT*?$' 结果为 True PS > 'ATTT' -match 'AT*?'; $Matches[0] 结果为 True ,匹配结果为 A |
| +? | 一次或多次匹配,尽可能少地匹配。 | PS > "A" -match '^AT+?$' 结果为 False PS > 'ATTT' -match 'AT+?'; $Matches[0] 结果为 True ,匹配结果为 AT |
| ?? | 零次或一次匹配,尽可能少地匹配。 | PS > "A" -match '^AT??$' 结果为 True PS > 'ATTT' -match 'AT??'; $Matches[0] 结果为 True ,匹配结果为 A |
| {n}? | 恰好 n 次匹配。 | PS > "TTTTT" -match '^T{5}?$' 结果为 True |
| {n,}? | n 次或更多次匹配,尽可能少地匹配。 | PS > "TTTTT" -match '^T{4,}?$' 结果为 True |
| {n,m}? | n m 次匹配(包含 n m ),尽可能少地匹配。 | PS > "TTTTT" -match '^T{4,6}?$' 结果为 True |

1.3 分组构造

分组构造允许对字符、模式和其他表达式进行分组,常见的分组构造及其描述如下表所示:
| 分组构造 | 描述 | 示例 |
| — | — | — |
| (text) | 捕获括号内匹配的文本。这些捕获根据左括号的顺序按数字命名(从 1 开始)。 | PS > "Hello" -match '^(.*)llo$'; $matches[1] 结果为 True ,匹配结果为 He |
| (?<name>) | 捕获括号内匹配的文本。这些捕获由 name 中给定的名称命名。 | PS > "Hello" -match '^(?<One>.*)llo$'; $matches.One 结果为 True ,匹配结果为 He |
| (?<name1 - name2>) | 平衡组定义。这是一种高级正则表达式构造,可用于匹配平衡的术语对。 | |
| (?:) | 非捕获组。 | PS > "A1" -match '((A|B)\d)'; $matches 结果为 True ,匹配结果为:
<br>Name Value<br>---- -----<br>2 A<br>1 A1<br>0 A1<br>
PS > "A1" -match '((?:A|B)\d)'; $matches 结果为 True ,匹配结果为:
<br>Name Value<br>---- -----<br>1 A1<br>0 A1<br> |
| (?imnsx - imnsx:) | 为该组应用或禁用给定的选项。支持的选项有: i (不区分大小写)、 m (多行模式)、 n (显式捕获)、 s (单行模式)、 x (忽略空白)。 | PS > "Te nst” -match ‘(T e.st)’ 结果为 False PS > “Te nst" -match '(?sx:T e.st)' 结果为 True |
| (?=) | 零宽度正向预查断言。确保给定模式在右侧匹配,但不实际执行匹配。 | PS > "555 - 1212" -match '(?=...-)(.*)'; $matches[1] 结果为 True ,匹配结果为 555 - 1212 |
| (?!) | 零宽度负向预查断言。确保给定模式在右侧不匹配,但不实际执行匹配。 | PS > "friendly" -match '(?!friendly)friend' 结果为 False |
| (?<=) | 零宽度正向后行断言。确保给定模式在左侧匹配,但不实际执行匹配。 | PS > "public int X" -match '^.*(?<=public )int .*$' 结果为 True |
| (?<!) | 零宽度负向后行断言。确保给定模式在左侧不匹配,但不实际执行匹配。 | PS > "private int X" -match '^.*(?<!private )int .*$' 结果为 False |
| (?> ) | 非回溯子表达式。仅当该子表达式能完全匹配时才匹配。 | PS > "Hello World" -match '(Hello.*)orld' 结果为 True PS > "Hello World" -match '(?>Hello.*)orld' 结果为 False |

1.4 原子零宽度断言

原子零宽度断言用于限制匹配可能发生的位置,常见的断言及其限制如下表所示:
| 断言 | 限制 | 示例 |
| — | — | — |
| ^ | 匹配必须发生在字符串的开头(如果启用了 Multiline 选项,则为行的开头)。 | PS > "Test" -match '^est' 结果为 False |
| $ | 匹配必须发生在字符串的末尾(如果启用了 Multiline 选项,则为行的末尾)。 | PS > "Test" -match 'Tes$' 结果为 False |
| \A | 匹配必须发生在字符串的开头。 | PS > "The nTest” -match ‘(?m:^Test)’ 结果为 True PS > “The nTest" -match '(?m:\ATest)' 结果为 False |
| \Z | 匹配必须发生在字符串的末尾,或在字符串末尾的 \n 之前。 | PS > "The nTest n" -match '(?m:The$)' 结果为 True PS > "The nTest n" -match '(?m:The\Z)' 结果为 False PS > "The nTest n" -match 'Test\Z' 结果为 True |
| \z | 匹配必须发生在字符串的末尾。 | PS > "The nTest n" -match 'Test\z' 结果为 False |
| \G | 匹配必须发生在前一个匹配结束的位置。与 System.Text.RegularExpressions.Match.NextMatch() 一起使用。 | |
| \b | 匹配必须发生在单词边界上:由非字母数字字符分隔的单词的第一个或最后一个字符。 | PS > "Testing" -match 'ing\b' 结果为 True |
| \B | 匹配不能发生在单词边界上。 | PS > "Testing" -match 'ing\B' 结果为 False |

1.5 替换模式

替换模式用于正则表达式的替换操作,常见的替换模式及其替换规则如下表所示:
| 模式 | 替换规则 | 示例 |
| — | — | — |
| $number | 由组号 number 匹配的文本。 | PS > "Test" -replace "(.*)st",'$1ar' 结果为 Tear |
| ${name} | 由名为 name 的组匹配的文本。 | PS > "Test" -replace "(?<pre>.*)st",'${pre}ar' 结果为 Tear |
| $$ | 文字 $ 。 | PS > "Test" -replace ".",'$$' 结果为 $$$$ |
| $& | 整个匹配的副本。 | PS > "Test" -replace "^.*$",'Found: $&' 结果为 Found: Test |
| $`` | 输入字符串中匹配之前的文本。 | PS > “Test” -replace “est$”,’Te$ ' 结果为 TTeT |
| $' | 输入字符串中匹配之后的文本。 | PS > "Test" -replace "^Tes",'Res$''' 结果为 Restt |
| $+ | 最后捕获的组。 | PS > "Testing" -replace "(.*)ing",'$+ed' 结果为 Tested |
| $_ | 整个输入字符串。 | PS > "Testing" -replace "(.*)ing",'String: $_' 结果为 String: Testing |

1.6 交替构造

交替构造允许执行“或”逻辑,常见的交替构造及其描述如下表所示:
| 交替构造 | 描述 | 示例 |
| — | — | — |
| | | 匹配由竖线字符分隔的任何项。 | PS > "Test" -match '(B|T)est' 结果为 True |
| (?(expression)yes|no) | 如果 expression 在该点匹配,则匹配 yes 项;否则,匹配 no 项。 no 项是可选的。 | PS > "3.14" -match '(?(\d)3.14|Pi)' 结果为 True PS > "Pi" -match '(?(\d)3.14|Pi)' 结果为 True PS > "2.71" -match '(?(\d)3.14|Pi)' 结果为 False |
| (?(name)yes|no) | 如果名为 name 的捕获组在该点有捕获,则匹配 yes 项;否则,匹配 no 项。 no 项是可选的。 | PS > "123" -match '(?<one>1)?(?(one)23|234)' 结果为 True PS > "23" -match '(?<one>1)?(?(one)23|234)' 结果为 False PS > "234" -match '(?<one>1)?(?(one)23|234)' 结果为 True |

1.7 反向引用构造

反向引用构造用于引用表达式中的捕获组,常见的反向引用构造及其引用规则如下表所示:
| 反向引用构造 | 引用对象 | 示例 |
| — | — | — |
| \number | 表达式中的组号 number 。 | PS > "|Text|" -match '(.)Text\1' 结果为 True PS > "|Text+" -match '(.)Text\1' 结果为 False |
| \k<name> | 表达式中名为 name 的组。 | PS > "|Text|" -match '(?<Symbol>.)Text\k<Symbol>' 结果为 True PS > "|Text+" -match '(?<Symbol>.)Text\k<Symbol>' 结果为 False |

1.8 其他构造

其他构造用于修改正则表达式,常见的构造及其描述如下表所示:
| 构造 | 描述 | 示例 |
| — | — | — |
| (?imnsx - imnsx) | 为表达式的其余部分应用或禁用给定的选项。支持的选项有: i (不区分大小写)、 m (多行模式)、 n (显式捕获)、 s (单行模式)、 x (忽略空白)。 | PS > "Te nst” -match ‘(?sx)T e.st’ 结果为 True | | (?# ) | 内联注释。注释在第一个右括号处结束。 | PS > “Test” -match ‘(?# Match ‘Test’)Test’ 结果为 True | | # [to end of line] | 当正则表达式启用了 IgnoreWhitespace 选项时允许的注释形式。 | PS > “Test” -match ‘(?x)Test # Matches Test’ 结果为 True` |

1.9 字符转义

字符转义用于表示另一个字符,常见的转义字符及其匹配规则如下表所示:
| 转义字符 | 匹配规则 |
| — | — |
| <ordinary characters> | 除 . $ ^ { [ ( | ) * + ? \ 之外的字符匹配自身。 |
| \a | 响铃(警报)字符 \u0007 。 |
| \b | 如果在 [] 字符类中,则为退格符 \u0008 。在正则表达式中, \b 表示单词边界(在 \w \W 字符之间),但在 [] 字符类中, \b 指退格符。在替换模式中, \b 始终表示退格符。 |
| \t | 制表符 \u0009 。 |
| \r | 回车符 \u000D 。 |
| \v | 垂直制表符 \u000B 。 |
| \f | 换页符 \u000C 。 |
| \n | 换行符 \u000A 。 |
| \e | 转义符 \u001B 。 |
| \ddd | 八进制表示的 ASCII 字符(最多三位数字)。如果数字没有前导零,且只有一位数字,或者对应于捕获组编号,则将其视为反向引用。 |
| \xdd | 十六进制表示的 ASCII 字符(恰好两位数字)。 |
| \cC | ASCII 控制字符;例如, \cC Control - C 。 |
| \udddd | 十六进制表示的 Unicode 字符(恰好四位数字)。 |
| \ | 当后面跟着一个未被识别为转义字符的字符时,匹配该字符。例如, \* 是文字字符 * 。 |

2. XPath 快速参考

XPath 是与 XML 交互的标准方式,就像正则表达式是与纯文本交互的标准方式一样。以下是 XPath 的基本概念和操作示例。

2.1 示例 XML

为了便于说明,使用以下示例 XML:

<AddressBook>
  <Person contactType="Personal">
    <Name>Lee</Name>
    <Phone type="home">555-1212</Phone>
    <Phone type="work">555-1213</Phone>
  </Person>
  <Person contactType="Business">
    <Name>Ariel</Name>
    <Phone>555-1234</Phone>
  </Person>
</AddressBook>

2.2 导航和选择

XPath 的导航和选择语法及其含义如下表所示:
| 语法 | 含义 | 示例 |
| — | — | — |
| / | 表示 XML 树的根。 | PS > $xml | Select-Xml "/" | Select -Expand Node 结果为:
<br>AddressBook<br>-----------<br>AddressBook<br> |
| /Node | 从 XML 树的根导航到名为 Node 的节点。 | PS > $xml | Select-Xml "/AddressBook" | Select -Expand Node 结果为:
<br>Person<br>------<br>{Lee, Ariel}<br> |
| /Node/*/Node2 | 通过 Node 导航到名为 Node2 的节点,允许中间有任意单个节点。 | PS > $xml | Select-Xml "/AddressBook/*/Name" | Select -Expand Node 结果为:
<br>#text<br>-----<br>Lee<br>Ariel<br> |
| //Node | 在 XML 树的任何位置查找名为 Node 的所有节点。 | PS > $xml | Select-Xml "//Phone" | Select -Expand Node 结果为:
<br>type #text<br>---- -----<br>home 555-1212<br>work 555-1213<br> 555-1234<br> |
| .. | 检索给定节点的父节点。 | PS > $xml | Select-Xml "//Phone" | Select -Expand Node
结果为:
<br>type #text<br>---- -----<br>home 555-1212<br>work 555-1213<br> 555-1234<br>
PS > $xml | Select-Xml "//Phone/.." | Select -Expand Node
结果为:
<br>contactType Name Phone<br>----------- ---- -----<br>Personal Lee {Phone, Phone}<br>Business Ariel 555-1234<br> |
| @Attribute | 访问名为 Attribute 的属性的值。 | PS > $xml | Select-Xml "//Phone/@type" | Select -Expand Node 结果为:
<br>#text<br>-----<br>home<br>work<br> |

2.3 比较

XPath 的比较语法及其含义如下表所示:
| 语法 | 含义 | 示例 |
| — | — | — |
| [ ] | 过滤,类似于 Where - Object cmdlet。 | PS > $xml | Select-Xml "//Person[@contactType = 'Personal']" | Select -Expand Node
结果为:
<br>contactType Name Phone<br>----------- ---- -----<br>Personal Lee {Phone, Phone}<br>
PS > $xml | Select-Xml "//Person[Name = 'Lee']" | Select -Expand Node
结果为:
<br>contactType Name Phone<br>----------- ---- -----<br>Personal Lee {Phone, Phone}<br> |
| and | 逻辑与。 | |
| or | 逻辑或。 | |
| not() | 逻辑非。 | |
| = | 相等。 | |
| != | 不相等。 | |

3. .NET 字符串格式化

3.1 字符串格式化语法

格式 -f 运算符支持的格式字符串包含格式项,每个格式项的形式为: {index[,alignment][:formatString]}
- index :表示格式运算符后面的对象数组中项的从零开始的索引。
- alignment :可选,用于表示项的对齐方式。正数将项右对齐到指定宽度的字段中,负数将项左对齐到指定宽度的字段中。
- formatString :可选,使用该类型的特定格式字符串语法格式化项。

示例代码如下:

PS > ("{0,6}" -f 4.99), ("{0,6:##.00}" -f 15.9)
  4.99
 15.90

3.2 标准数字格式字符串

标准数字格式字符串及其说明和示例如下表所示:
| 格式说明符 | 名称 | 描述 | 示例 |
| — | — | — | — |
| C c | 货币 | 货币金额。 | PS > "{0:C}" -f 1.23 结果为 $1.23 |
| D d | 十进制 | 十进制金额(适用于整数类型)。精度说明符控制结果中的最小数字位数。 | PS > "{0:D4}" -f 2 结果为 0002 |
| E e | 科学计数法 | 科学(指数)表示法。精度说明符控制小数点后的数字位数。 | PS > "{0:E3}" -f [Math]::Pi 结果为 3.142E+000 |
| F f | 定点数 | 定点表示法。精度说明符控制小数点后的数字位数。 | PS > "{0:F3}" -f [Math]::Pi 结果为 3.142 |
| G g | 通用 | 数字的最紧凑表示形式(在定点和科学计数法之间)。精度说明符控制有效数字的位数。 | PS > "{0:G3}" -f [Math]::Pi 结果为 3.14
PS > "{0:G3}" -f 1mb 结果为 1.05E+06 |
| N n | 数字 | 数字的人类可读形式,包括数字组之间的分隔符。精度说明符控制小数点后的数字位数。 | PS > "{0:N4}" -f 1mb 结果为 1,048,576.0000 |
| P p | 百分比 | 数字(通常在 0 到 1 之间)表示为百分比。精度说明符控制小数点后的数字位数。 | PS > "{0:P4}" -f 0.67 结果为 67.0000 % |
| R r | 往返 | 以保证解析后的字符串将再次得到原始数字的精度格式化的 Single Double 数字。 | PS > "{0:R}" -f (1mb/2.0) 结果为 524288
PS > "{0:R}" -f (1mb/9.0) 结果为 116508.44444444444 |
| X x | 十六进制 | 将数字转换为十六进制数字字符串。说明符的大小写控制结果十六进制数字的大小写。精度说明符控制结果字符串中的最小数字位数。 | PS > "{0:X4}" -f 1324 结果为 052C |

3.3 自定义数字格式字符串

自定义数字格式字符串可以实现标准格式字符串不支持的数字格式化方式,常见的格式说明符及其描述和示例如下表所示:
| 格式说明符 | 名称 | 描述 | 示例 |
| — | — | — | — |
| 0 | 零占位符 | 指定数字字符串的精度和宽度。未与原始数字中的数字匹配的零将作为零输出。 | PS > "{0:00.0}" -f 4.12341234 结果为 04.1 |
| # | 数字占位符 | 指定数字字符串的精度和宽度。输入数字中未与 # 符号匹配的数字不会输出。 | PS > "{0:##.#}" -f 4.12341234 结果为 4.1 |
| . | 小数点 | 确定小数点的位置。 | PS > "{0:##.#}" -f 4.12341234 结果为 4.1 |
| , | 千位分隔符 | 当放置在格式化字符串中小数点前的零或数字占位符之间时,在数字组之间添加分隔符字符。 | PS > "{0:#,#.#}" -f 1234.121234 结果为 1,234.1 |
| , | 数字缩放 | 当放置在格式化字符串中文字(或隐式)小数点之前时,将输入除以 1,000。可以多次应用此格式说明符。 | PS > "{0:##,,.000}" -f 1048576 结果为 1.049 |
| % | 百分比占位符 | 将输入乘以 100,并在格式说明符中显示的位置插入百分号。 | PS > "{0:%##.000}" -f .68 结果为 %68.000 |
| E0 E+0 E - 0 e0 e+0 e - 0 | 科学计数法 | 以科学计数法显示输入。 E 后面的零的数量定义了指数字段的最小长度。 | PS > "{0:##.#E000}" -f 2.71828 结果为 27.2E-001 |
| ' text ' " text " | 文字字符串 | 将提供的文本逐字插入输出中,不影响格式化。 | PS > "{0:#.00'##'}" -f 2.71828 结果为 2.72## |
| ; | 部分分隔符 | 允许进行条件格式化。如果格式说明符中没有部分分隔符,则格式化语句适用于所有输入;如果有一个分隔符(创建两个部分),则第一部分适用于正数和零,第二部分适用于负数;如果有两个分隔符(创建三个部分),则这些部分分别适用于正数、负数和零。 | PS > "{0:POS;NEG;ZERO}" -f -14 结果为 NEG |
| 其他 | 其他字符 | 将提供的文本逐字插入输出中,不影响格式化。 | PS > "{0:$## Please}" -f 14 结果为 $14 Please |

4. .NET DateTime 格式化

4.1 标准 DateTime 格式字符串

标准 DateTime 格式字符串可以将 DateTime 对象转换为几种标准格式,常见的格式说明符及其名称、描述和示例如下表所示:
| 格式说明符 | 名称 | 描述 | 示例 |
| — | — | — | — |
| d | 短日期 | 文化特定的短日期格式。 | PS > "{0:d}" -f [DateTime] "01/23/4567" 结果为 1/23/4567 |
| D | 长日期 | 文化特定的长日期格式。 | PS > "{0:D}" -f [DateTime] "01/23/4567" 结果为 Friday, January 23, 4567 |
| f | 完整日期/短时间 | 结合长日期和短时间格式模式。 | PS > "{0:f}" -f [DateTime] "01/23/4567" 结果为 Friday, January 23, 4567 12:00 AM |
| F | 完整日期/长时间 | 结合长日期和长时间格式模式。 | PS > "{0:F}" -f [DateTime] "01/23/4567" 结果为 Friday, January 23, 4567 12:00:00 AM |
| g | 常规日期/短时间 | 结合短日期和短时间格式模式。 | PS > "{0:g}" -f [DateTime] "01/23/4567" 结果为 1/23/4567 12:00 AM |
| G | 常规日期/长时间 | 结合短日期和长时间格式模式。 | PS > "{0:G}" -f [DateTime] "01/23/4567" 结果为 1/23/4567 12:00:00 AM |
| M m | 月日 | 文化特定的月日格式。 | PS > "{0:M}" -f [DateTime] "01/23/4567" 结果为 January 23 |
| o | 往返日期/时间 | 以保证解析后的字符串将再次得到原始 DateTime 的模式格式化日期。 | PS > "{0:o}" -f [DateTime] "01/23/4567" 结果为 4567-01-23T00:00:00.0000000 |
| R r | RFC1123 | 标准的 RFC1123 格式模式。 | PS > "{0:R}" -f [DateTime] "01/23/4567" 结果为 Fri, 23 Jan 4567 00:00:00 GMT |
| s | 可排序 | 可排序的格式模式。符合 ISO 8601 标准,提供适合排序的输出。 | PS > "{0:s}" -f [DateTime] "01/23/4567" 结果为 4567-01-23T00:00:00 |
| t | 短时间 | 文化特定的短时间格式。 | PS > "{0:t}" -f [DateTime] "01/23/4567" 结果为 12:00 AM |
| T | 长时间 | 文化特定的长时间格式。 | PS > "{0:T}" -f [DateTime] "01/23/4567" 结果为 12:00:00 AM |
| u | 通用可排序 | 文化特定的通用可排序 DateTime 格式应用于输入的 UTC 等效值。 | PS > "{0:u}" -f [DateTime] "01/23/4567" 结果为 4567-01-23 00:00:00Z |
| U | 通用 | 文化特定的完整 DateTime 格式应用于输入的 UTC 等效值。 | PS > "{0:U}" -f [DateTime] "01/23/4567" 结果为 Friday, January 23, 4567 8:00:00 AM |
| Y y | 年月 | 文化特定的年月格式。 | PS > "{0:Y}" -f [DateTime] "01/23/4567" 结果为 January, 4567 |

4.2 自定义 DateTime 格式字符串

自定义 DateTime 格式字符串可以实现标准格式字符串不支持的日期格式化方式,常见的格式说明符及其描述和示例如下表所示:
| 格式说明符 | 描述 | 示例 |
| — | — | — |
| d | 月份中的日期,范围为 1 到 31。单数字日期不包含前导零。 | PS > "{0:%d}" -f [DateTime] "01/02/4567" 结果为 2 |
| dd | 月份中的日期,范围为 1 到 31。单数字日期包含前导零。 | PS > "{0:dd}" -f [DateTime] "01/02/4567" 结果为 02 |
| ddd | 星期几的缩写名称。 | PS > "{0:ddd}" -f [DateTime] "01/02/4567" 结果为 Fri |
| dddd | 星期几的完整名称。 | PS > "{0:dddd}" -f [DateTime] "01/02/4567" 结果为 Friday |
| f | 秒的小数部分(毫秒)的最高有效数字。 |

PS > $date = Get-Date
PS > $date.Millisecond
93
PS > "{0:%f}" -f $date
0

|
| ff | 秒的小数部分(毫秒)的前两位最高有效数字。 |

PS > $date = Get-Date
PS > $date.Millisecond
93
PS > "{0:ff}" -f $date
09

|
| fff | 秒的小数部分(毫秒)的前三位最高有效数字。 |

PS > $date = Get-Date
PS > $date.Millisecond
93
PS > "{0:fff}" -f $date
093

|
| ffff | 秒的小数部分(毫秒)的前四位最高有效数字。 |

PS > $date = Get-Date
PS > $date.Millisecond
93
PS > "{0:ffff}" -f $date
0937

|
| fffff | 秒的小数部分(毫秒)的前五位最高有效数字。 |

PS > $date = Get-Date
PS > $date.Millisecond
93
PS > "{0:fffff}" -f $date
09375

|
| ffffff | 秒的小数部分(毫秒)的前六位最高有效数字。 |

PS > $date = Get-Date
PS > $date.Millisecond
93
PS > "{0:ffffff}" -f $date
093750

|
| fffffff | 秒的小数部分(毫秒)的前七位最高有效数字。 |

PS > $date = Get-Date
PS > $date.Millisecond
93
PS > "{0:fffffff}" -f $date
0937500

|
| F FF FFF (...) FFFFFFF | 秒的小数部分(毫秒)的最高有效数字。与小写的 f 系列说明符相比,如果数字为零,则不显示任何内容。 | PS > "{0:|F FF FFF FFFF|}" -f [DateTime] "01/02/4567" 结果为 | | |
| %g gg | 纪元(例如, A.D. )。 | PS > "{0:gg}" -f [DateTime] "01/02/4567" 结果为 A.D. |
| %h | 小时,范围为 1 到 12。单数字小时不包含前导零。 | PS > "{0:%h}" -f [DateTime] "01/02/4567 4:00pm" 结果为 4 |
| hh | 小时,范围为 01 到 12。单数字小时包含前导零。注意:除非与其他格式化说明符一起使用,否则这将被解释为标准 DateTime 格式化字符串。 | PS > "{0:hh}" -f [DateTime] "01/02/4567 4:00pm" 结果为 04 |
| %H | 小时,范围为 0 到 23。单数字小时不包含前导零。 | PS > "{0:%H}" -f [DateTime] "01/02/4567 4:00pm" 结果为 16 |
| HH | 小时,范围为 00 到 23。单数字小时包含前导零。 | PS > "{0:HH}" -f [DateTime] "01/02/4567 4:00am" 结果为 04 |
| K | 对应于输入日期的类型(即 Local Utc Unspecified )的 DateTime.Kind 说明符。 | PS > "{0:%K}" -f [DateTime]::Now.ToUniversalTime() 结果为 Z |
| m | 分钟,范围为 0 到 59。单数字分钟不包含前导零。 | PS > "{0:%m}" -f [DateTime]::Now 结果为 7 |
| mm | 分钟,范围为 00 到 59。单数字分钟包含前导零。 | PS > "{0:mm}" -f [DateTime]::Now 结果为 08 |
| M | 月份,范围为 1 到 12。单数字月份不包含前导零。 | PS > "{0:%M}" -f [DateTime] "01/02/4567" 结果为 1 |
| MM | 月份,范围为 01 到 12。单数字月份包含前导零。 | PS > "{0:MM}" -f [DateTime] "01/02/4567" 结果为 01 |
| MMM | 月份的缩写名称。 | PS > "{0:MMM}" -f [DateTime] "01/02/4567" 结果为 Jan |
| MMMM | 月份的完整名称。 | PS > "{0:MMMM}" -f [DateTime] "01/02/4567" 结果为 January |
| s | 秒,范围为 0 到 59。单数字秒不包含前导零。 |

PS > $date = Get-Date
PS > "{0:%s}" -f $date
7

|
| ss | 秒,范围为 00 到 59。单数字秒包含前导零。 |

PS > $date = Get-Date
PS > "{0:ss}" -f $date
07

|
| t | a.m./p.m. 指示符的第一个字符。 |

PS > $date = Get-Date
PS > "{0:%t}" -f $date
P

|
| tt | a.m./p.m. 指示符。 |

PS > $date = Get-Date
PS > "{0:tt}" -f $date
PM

|
| y | 年份,最多两位数字。 | PS > "{0:%y}" -f [DateTime] "01/02/4567" 结果为 67 |
| yy | 年份,最多两位数字。 | PS > "{0:yy}" -f [DateTime] "01/02/4567" 结果为 67 |
| yyy | 年份,最多四位数字。 | PS > "{0:yyy}" -f [DateTime] "01/02/4567" 结果为 4567 |
| yyyy | 年份,最多四位数字。 | PS > "{0:yyyy}" -f [DateTime] "01/02/4567" 结果为 4567 |
| yyyyy | 年份,最多五位数字。 | PS > "{0:yyyy}" -f [DateTime] "01/02/4567" 结果为 04567 |
| z | 与 GMT 的带符号时区偏移量,不包含前导零。 | PS > "{0:%z}" -f [DateTime]::Now 结果为 -8 |
| zz | 与 GMT 的带符号时区偏移量,包含前导零。 | PS > "{0:zz}" -f [DateTime]::Now 结果为 -08 |
| zzz | 与 GMT 的带符号时区偏移量,以小时和分钟为单位。 | PS > "{0:zzz}" -f [DateTime]::Now 结果为 -08:00 |
| : | 时间分隔符。 | PS > "{0:y/m/d h:m:s}" -f [DateTime] "01/02/4567 4:00pm" 结果为 67/0/2 4:0:0 |
| / | 日期分隔符。 | PS > "{0:y/m/d h:m:s}" -f [DateTime] "01/02/4567 4:00pm" 结果为 67/0/2 4:0:0 |
| " text " ' text ' | 将提供的文本逐字插入输出中,不影响格式化。 | PS > "{0:'Day: 'dddd}" -f [DateTime]::Now 结果为 Day: Monday |
| %c | 允许使用单字符自定义格式化说明符的语法。 % 符号不会添加到输出中。 | PS > "{0:%h}" -f [DateTime] "01/02/4567 4:00pm" 结果为 4 |
| 其他 | 将提供的文本逐字插入输出中,不影响格式化。 | PS > "{0:dddd!}" -f [DateTime]::Now 结果为 Monday! |

综上所述,正则表达式、XPath、.NET 字符串格式化和 .NET DateTime 格式化在文本处理、XML 操作和数据展示等方面都有着重要的应用。通过熟练掌握这些知识和技能,可以更高效地完成各种编程任务。

5. 总结与应用建议

5.1 各知识点总结

  • 正则表达式 :功能强大,用于文本解析和匹配。通过字符类、量词、分组构造等多种元素,可以灵活定义匹配规则,满足不同的文本处理需求。例如,在数据清洗、信息提取等场景中,正则表达式能够快速准确地定位和处理特定的文本模式。
  • XPath :是与 XML 交互的标准方式,通过导航和选择语法可以方便地定位 XML 树中的节点,结合比较语法能够对节点进行过滤和筛选。在处理 XML 数据时,如解析配置文件、提取特定信息等,XPath 能大大提高开发效率。
  • .NET 字符串格式化 :提供了丰富的标准和自定义格式字符串,可根据不同的需求对数字和日期时间进行格式化。在数据展示、报表生成等场景中,合理使用字符串格式化可以使数据呈现更加清晰和规范。

5.2 应用建议

  • 正则表达式的应用
    • 在使用正则表达式时,应尽量避免过于复杂的模式,以免影响性能和可读性。可以先从简单的模式开始,逐步构建和优化。
    • 对于复杂的匹配需求,可以使用分组构造和命名捕获组,方便后续对匹配结果的处理和引用。
    • 注意正则表达式的性能问题,特别是在处理大量数据时,避免使用过于贪婪的量词,以免导致性能下降。
  • XPath 的应用
    • 在编写 XPath 表达式时,要充分理解 XML 文档的结构,合理使用导航和选择语法,确保能够准确地定位到所需的节点。
    • 对于复杂的筛选条件,可以结合比较语法和逻辑运算符,实现更精确的节点过滤。
    • 在处理大型 XML 文档时,考虑使用缓存机制,避免重复解析和查询,提高性能。
  • .NET 字符串格式化的应用
    • 根据不同的业务需求选择合适的标准或自定义格式字符串,确保数据的格式化符合预期。
    • 在处理数字格式化时,注意精度和舍入规则,避免数据丢失或误差。
    • 对于日期时间格式化,要考虑不同文化背景下的格式差异,确保数据在不同环境下的一致性。

5.3 实际应用示例

以下通过一个综合示例展示如何结合使用上述知识来完成一个实际的编程任务。

假设我们有一个包含人员信息的 XML 文件,需要从中提取特定人员的信息,并对提取的数据进行格式化输出。示例 XML 文件如下:

<Persons>
  <Person>
    <Name>John</Name>
    <Age>30</Age>
    <BirthDate>1993-01-15</BirthDate>
  </Person>
  <Person>
    <Name>Jane</Name>
    <Age>25</Age>
    <BirthDate>1998-05-20</BirthDate>
  </Person>
</Persons>

我们的目标是提取姓名为 John 的人员信息,并将其年龄格式化为带逗号的数字,出生日期格式化为长日期格式。以下是实现该功能的 PowerShell 代码:

# 加载 XML 文件
$xml = [xml](Get-Content -Path "persons.xml")

# 使用 XPath 选择姓名为 John 的人员节点
$person = $xml.SelectSingleNode("//Person[Name='John']")

# 提取姓名、年龄和出生日期
$name = $person.Name
$age = [int]$person.Age
$birthDate = [DateTime]$person.BirthDate

# 格式化年龄和出生日期
$formattedAge = "{0:N0}" -f $age
$formattedBirthDate = "{0:D}" -f $birthDate

# 输出格式化后的信息
Write-Host "Name: $name"
Write-Host "Age: $formattedAge"
Write-Host "Birth Date: $formattedBirthDate"

在上述代码中,我们首先使用 [xml] 类型转换将 XML 文件加载到内存中,然后使用 XPath 表达式 //Person[Name='John'] 选择姓名为 John 的人员节点。接着,我们提取该节点中的姓名、年龄和出生日期,并使用 .NET 字符串格式化对年龄和出生日期进行格式化。最后,我们将格式化后的信息输出到控制台。

通过这个示例,我们可以看到如何结合正则表达式、XPath 和 .NET 字符串格式化来完成一个实际的编程任务,提高开发效率和代码的可读性。

5.4 常见问题及解决方法

  • 正则表达式匹配不准确
    • 问题描述 :正则表达式模式无法准确匹配预期的文本。
    • 解决方法 :检查正则表达式的语法和逻辑,确保模式的定义符合需求。可以使用调试工具或测试用例逐步验证模式的匹配情况,找出问题所在。
  • XPath 查询结果为空
    • 问题描述 :使用 XPath 表达式查询 XML 文档时,没有返回预期的节点。
    • 解决方法 :检查 XPath 表达式的语法和路径是否正确,确保能够准确定位到所需的节点。同时,检查 XML 文档的结构和命名空间,避免因命名空间问题导致查询失败。
  • .NET 字符串格式化结果不符合预期
    • 问题描述 :使用 .NET 字符串格式化时,输出结果不符合预期。
    • 解决方法 :检查格式字符串的语法和参数是否正确,确保使用的格式说明符和精度设置符合需求。同时,注意数据类型的转换,避免因数据类型不匹配导致格式化失败。

5.5 未来发展趋势

随着技术的不断发展,正则表达式、XPath 和 .NET 字符串格式化等技术也在不断演进和完善。未来,我们可以期待以下发展趋势:
- 更强大的功能和性能 :正则表达式和 XPath 可能会支持更多的高级特性和优化算法,提高匹配和查询的效率。 .NET 字符串格式化也可能会提供更多的自定义选项和更灵活的格式控制。
- 更好的跨平台支持 :随着跨平台开发的需求不断增加,这些技术可能会更好地支持不同的操作系统和开发环境,方便开发者在不同平台上进行应用开发。
- 与人工智能和机器学习的结合 :在文本处理和数据分析领域,正则表达式和 XPath 可能会与人工智能和机器学习技术相结合,实现更智能的文本分析和数据挖掘。

通过不断学习和掌握这些技术的最新发展,我们可以更好地应对未来的编程挑战,提高开发效率和代码质量。

总之,正则表达式、XPath 和 .NET 字符串格式化是编程中非常重要的工具,掌握它们的使用方法和技巧对于提高编程能力和解决实际问题具有重要意义。希望本文的介绍和示例能够帮助读者更好地理解和应用这些技术,在实际开发中取得更好的效果。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值