掌握 PowerShell 字符串:连接、分割等

字符串在 PowerShell 中可能是最常用的数据类型之一PowerShell。 无论是显示消息、提示输入,还是将数据发送到文件,几乎不可能在没有涉及字符串的情况下编写脚本。

在本文中,您将了解到字符串不仅仅用于阅读和显示。它们还可以被操纵以适应您可能为其编写脚本的任何任务的目的。比如,替换字符或整个单词,将字符串连接起来形成一个新的字符串,甚至将一个字符串拆分成多个字符串。

理解字符串

根据 .NET 对字符串的定义 – “字符串是一个用于表示文本的字符的顺序集合”。 简而言之,只要有一系列形成文本的字符,就有一个字符串。

在 PowerShell 中定义系统字符串

通过将一系列字符括在单引号或双引号中来定义字符串。以下是字符串的示例。

PS> 'Hello PowerShell - Today is $(Get-Date)'PS> "Hello PowerShell - Today is $(Get-Date)"

实际上,字符串在 .NET 中是 System.Strings。

正如您从上面的示例中看到的,第一个字符串用单引号括起,而第二个字符串用双引号括起。如果您想知道,两者之间唯一的区别在于双引号中的字符串支持字符串扩展,而单引号只表示字面字符串。

要确认单引号与双引号的概念,请在 PowerShell 中粘贴上面示例中的两个字符串。

以下截图显示单引号字符串返回确切的字面字符串定义。而双引号字符串返回Get-Date cmdlet的表达式结果的字符串。

Single Quote vs. Double-Quote String Output

上面显示的结果展示了在定义字符串时何时适合使用单引号或双引号的区别。

字符串对象

如前一节所述,形成文本的字符集合是一个字符串。字符串的结果值是String对象。字符串对象是一个.NET对象,类型为[System.String]

由于System.String是一个对象,它具有您可以使用Get-Member cmdlet访问的属性。以下我们在双引号字符串中插入一个变量。

PS> "Hello PowerShell - Today is $(Get-Date)" | Get-Member=

以下截图显示了String对象的TypeName和部分属性列表。

String Object properties

连接 PowerShell 字符串

字符串连接被描述为将两个或多个字符串连接在一起,从而从多个单独的字符串对象创建一个字符串对象。在 PowerShell 中连接字符串有几种方法。每种方法都不同,使用哪种取决于您计划如何实现字符串连接。

A typical example of using string concatenation in the real world is Active Directory user creation. Perhaps you’re creating a user creation script that takes the first name, last name, and department values from a list.

使用字符串连接,您可以为名称、显示名称、用户名和电子邮件地址制定标准命名约定。对于此示例,您将使用下面显示的字符串。将此代码复制并粘贴到您的 PowerShell 会话中。

$domain = 'contoso.com'
$firstname = 'Jack'
$lastname = 'Ripper'
$department = 'Health'

使用上述示例变量值,目标是通过连接字符串来得出以下列出的值。

  • 名称 = firstname lastname
  • 显示名称 = firstname lastname (department)
  • SamAccountName = firstname.lastname
  • 电子邮件地址 = [email protected]

在接下来的部分中,将使用 PowerShell 中可用的不同字符串连接方法创建上述列出的值。

让我们开始吧!

使用 PowerShell 字符串连接运算符

编程语言都有自己的字符串连接运算符,用于连接字符串。例如,在 Visual Basic 中,连接方法是和号(&)。PowerShell 也有自己的连接方法,即加号(+)。

使用字符串连接运算符,您可以使用以下代码连接字符串。

## 名称
$firstname + ' ' + $lastname
## 显示名称
$firstname + ' ' + $lastname + ' (' + $department + ')'
## SamAccountName
$firstname + '.' + $lastname
## 电子邮件地址
$firstname + '.' + $lastname + '@' + $domain

使用 PowerShell 字符串扩展

在连接字符串时,使用字符串扩展可能是生成最短代码的方法。您可以从下面的代码中看到,所需的全部操作就是按照字符串应出现的顺序排列它们,并将其置于双引号内。

# 使用字符串扩展
## 名称
"$firstname $lastname"
## 显示名称
"$firstname $lastname ($department)"
## SamAccountName
"$firstname.$lastname"
## 电子邮件地址
"$firstname.$lastname@$domain"

然后,PowerShell 解释和处理双引号字符串中的字符串扩展,以输出连接的字符串作为结果。您可以参考下面的示例输出。

Using String Expansion

使用 PowerShell 格式运算符

格式运算符(-f)主要用于复合格式。重要的是要记住,使用此方法时,有三个部分要注意:-f

请参考下面代码的第三行。 "{0} {1}" 表示格式和占位符。花括号中的数字表示要在其中显示的集合中字符串的索引。引号可以是单引号或双引号。

在此示例中,输入的字符串集合由 $firstname,$lastname 表示。这意味着 $firstname 变量的索引是 0,而 $lastname 则为 1。

最后,-f是占位符和由(-f)表示的字符串集合之间的位置。

## 名称
"{0} {1}" -f $firstname,$lastname
## 显示名称
"{0} {1} ({2})" -f $firstname,$lastname,$department
## SamAccountName
"{0}.{1}" -f $firstname,$lastname
## 电子邮件地址
"{0}.{1}@{2}" -f $firstname,$lastname,$domain

以上代码将产生以下结果。

Using the Format Operator

使用 PowerShell -Join 运算符

-Join 运算符可以通过两种方式将字符串连接成一个字符串。

使用 -Join 的第一种方式是在其后跟随要连接的字符串数组。 -Join 运算符不提供添加分隔符的选项。 数组中的所有字符串将直接拼接在一起。

-Join <String[]>

使用 -Join 运算符的第二种方式是指定要使用的分隔符。 字符串数组将连接在一起,但指定的分隔符字符将插入到每个字符串之间。

<String[]> -Join <Delimiter>

回到连接字符串的目标,下面的代码演示了如何使用 -Join 运算符来组合字符串。

## 名称
$firstname, $lastname -join ' '
## 显示名称
$firstname,$lastname,"($department)" -join ' '
## SamAccountName
-join ($firstname,'.',$lastname)
## 电子邮件地址
-join ($firstname,'.',$lastname,'@',$domain)

当您在PowerShell中运行上面的示例代码时,您期望看到类似下面显示的输出。

Using the PowerShell Join Operator

.NET String.Format() 方法

.NET String.Format 方法PowerShell 格式操作符 的.NET 对应方法。它的操作与格式操作符相同,需要指定格式和占位符。

## 名称
[string]::Format("{0} {1}",$firstname,$lastname)
## 显示名称
[string]::Format("{0} {1} ({2})",$firstname,$lastname,$department)
## SamAccountName
[string]::Format("{0}.{1}",$firstname,$lastname)
## 电子邮件地址
[string]::Format("{0}.{1}@{2}",$firstname,$lastname,$domain)

下面的截图展示了String.Format 方法的效果。

The .NET String.Format Method

.NET String.Concat() 方法

另一种连接字符串的方法是使用.Net String.Concat 方法。 .NET String.Concat 方法是 PowerShell 字符串连接操作符(+)的.NET 对应方法。但是,与使用 + 号连接字符串不同,您可以将所有字符串添加到方法中,就像这样 – [string]::Concat(string1,string2...)

## 名称
[string]::Concat($firstname,' ',$lastname)
## 显示名称
[string]::Concat($firstname,' ',$lastname,' (',$department,')')
## SamAccountName
[string]::Concat($firstname,'.',$lastname)
## 电子邮件地址
[string]::Concat($firstname,'.',$lastname,'@',$domain)

下面的截图演示了调用.NET String.Concat方法的结果。您可以看到,PowerShell已经合并了string1、string2。

Using the .NET String.Concat Method

.NET String.Join() 方法

.NET String.Join方法是PowerShell Join Operator (-join) 的.NET方法对应项。该方法的格式为[string]::Join(<delimiter>,<string1>,<string2>,...)

-Join 方法中的第一项始终是分隔符。然后,后续的项目值是要连接的字符串。请参见下面的示例代码。请记住,第一项始终是分隔符。如果您不想添加分隔符,可以指定这个 —> ''

## 名称
[string]::Join(' ',$firstname,$lastname)
## 显示名称
[string]::Join(' ',$firstname,$lastname,"($department)")
## SamAccountName
[string]::Join('',$firstname,'.',$lastname)
## 电子邮件地址
[string]::Join('',$firstname,'.',$lastname,'@',$domain)
The .NET String.Join Method

拆分PowerShell字符串

在前一节中,您已经看到了几种连接字符串的不同方法。在本节中,您将了解使用PowerShell拆分字符串的不同方法。拆分字符串是连接的反向操作。

你可以用两种不同的方式在 PowerShell 中拆分字符串——split()函数/方法或split运算符。

使用split()方法拆分字符串

如果你想要一种简单的方法来拆分字符串以创建一个数组,那么不用再找了,split()方法就是你的不二选择。split()方法存在于每个字符串对象上,能够根据一个非正则表达式字符将字符串拆分成数组。

例如,如果你有一个类似green|eggs|and|ham的字符串,你想要创建一个类似@('green','eggs','and','ham')的数组,你可以像下面的代码片段中那样使用竖线符号(|)来拆分这个字符串。

$string = 'green|eggs|and|ham'
$string.split('|')

然后你会看到 PowerShell 用竖线符号将字符串拆分成了期望的数组。

split()方法是拆分字符串的简单方式,但是有局限性。split()方法不允许通过正则表达式来拆分字符串。如果你需要更高级的功能来拆分字符串,你需要了解split运算符。

-split运算符

在 PowerShell 中用于拆分字符串的主要运算符是-Split运算符。使用-Split运算符,默认情况下会根据空格拆分字符串,或者使用特定的分隔字符。

下面是-Split运算符的语法,供你参考。请注意一元拆分和二元拆分之间的区别。

# 一元分割
-Split <String>
-Split (<String[]>)

# 二元分割
<String> -Split <Delimiter>[,<Max-substrings>[,"<Options>"]]
<String> -Split {<ScriptBlock>} [,<Max-substrings>]

在这个示例中,$string 变量保存了单行字符串的值。然后,使用 -Split 运算符,单行字符串将被分割成一个 PowerShell 字符串数组。分割后的字符串结果保存到 $split 变量中。

## 将字符串分割成子字符串
# 为 $string 变量赋一个字符串值
$string = 'This sentence will be split between whitespaces'
# 分割 $string 的值并将结果存储到 $split 变量中
$split = -split $string
# 获取结果子字符串的计数
$split.Count
# 显示结果子字符串
$split

从上面的结果中可以看到,最初的单个字符串被分割成了 7 个子字符串。这演示了 PowerShell 如何将一个字符串分割成数组。

字符分隔符

在前面的示例中,-Split 运算符即使没有指定一个 分隔符,也将单个字符串对象分割成多个子字符串;这是因为 -Split 运算符的默认分隔符是空格。但是,分隔符也可以是字符、字符串、模式或脚本块。

在这个示例中,使用的分隔符是分号 ;

## 使用分隔符将字符串拆分为子字符串
# 将字符串值赋给变量 $string
$string = 'This;sentence;will;be;split;between;semicolons'
# 将 $string 的值拆分并将结果存储到变量 $split 中
$split = $string -split ";"
# 获取拆分后子字符串的数量
$split.Count
# 显示拆分后的子字符串
$split

当您在 PowerShell 中测试上述代码时,将获得以下结果。

Splitting a String into Substrings with Character Delimiter

从上述输出中可以看出,分隔符字符在结果的子字符串中被完全省略了。

如果由于某种原因您需要保留分隔符字符,可以将字符括在括号中来保留分隔符。

$split = $string -split "(;)"
$split.Count
$split

在修改了分隔符后,运行代码将得到如下输出。

Splitting a string on semicolon

上面的结果显示了分隔符字符没有被省略,并且被计算在结果的子字符串中。

字符串分隔符

字符串还可以根据另一个字符串作为分隔符进行拆分。在此示例中,字符串“day”被用作分隔符。

$daysOfTheWeek= 'monday,tuesday,wednesday,thursday,friday,saturday,sunday'
$daysOfTheWeek -split "day"

脚本块分隔符

A scriptBlock as the delimiter enables the -Split operator to perform custom or complex splitting of strings.

在前面的示例中,分隔符字符或字符串用于拆分字符串。通过使用脚本块,您可以创建一个表达式,有效地使用多个分隔符。

以下是一个示例,使用表达式 {$PSItem -eq 'e' -or $PSItem -eq 'y'},这意味着如果传入字符为 'e''a',则字符串将被拆分。

$daysOfTheWeek= 'monday,tuesday,wednesday,thursday,friday,saturday,sunday'
$daysOfTheWeek -split {$PSItem -eq 'e' -or $PSItem -eq 'y'}

当你运行上面的命令时,输出将是使用脚本块中指定的表达式内的分隔符字符拆分的子字符串。

Splitting a String into Substrings with a Script Block Delimiter

这个下一个示例在脚本块中做了更多的事情。这次,表达式评估是否:

  • 传入字符被视为整数;以及
  • 其值是否大于1

如果评估的结果为真,则 -Split 运算符将使用该字符作为分隔符。此外,添加了错误处理以确保过滤掉错误。

$daysOfTheWeek= 'monday1tuesday2wednesday3thursday1friday4saturday8sunday'
$daysOfTheWeek -split {
    try {
        [int]$PSItem -gt 1
    }
    catch {
        #什么都不做
    }
}

运行上面显示的代码后,期望的结果是字符串将在可以将字符值转换为大于1的整数的地方进行拆分。以下显示了预期的输出。

Splitting a String into Substrings with a Script Block Delimiter

正则表达式分隔符

默认情况下,-Split 运算符使用匹配指定分隔符的正则表达式。这意味着你还可以使用正则表达式作为拆分字符串的分隔符。

在下一个示例中,字符串包含单词字符和非单词字符。目标是使用任何非单词字符拆分字符串。在正则表达式中,非单词字符由\W表示,而匹配这些字符的单词字符 – [a-zA-Z0-9_]\w表示。

$daysOfTheWeek= 'monday=tuesday*wednesday^thursday#friday!saturday(sunday'
$daysOfTheWeek -split "\W"

限制子字符串

还可以停止-Split运算符将字符串拆分为若干子字符串。用于实现限制结果的子字符串的选项是<Max-substrings>参数。

当您参考-Split语法时,<Max-substrings>参数是直接跟在<Delimited>参数后面的参数。下面再次显示了该语法以供参考。

<String> -Split <Delimiter>[,<Max-substrings>[,"<Options>"]]

根据上述语法,下面的示例代码被修改为将拆分/子字符串的数量限制为3。

$daysOfTheWeek= 'monday,tuesday,wednesday,thursday,friday,saturday,sunday'
$daysOfTheWeek -split ",",3

运行上面的代码将产生以下输出。从下面的输出中可以看出,字符串仅被拆分为三个子字符串。剩余的分隔符被跳过。

Limiting the Number of Substrings starting from the first 3 matched delimiters

现在,如果您想要限制子字符串,但是反向进行,您可以将<Max-substrings>参数值更改为负值。在下一个示例中,<Max-substrings>更改为-3

$daysOfTheWeek= 'monday,tuesday,wednesday,thursday,friday,saturday,sunday'
$daysOfTheWeek -split ",",-3

由于上述修改后的代码,字符串从最后三个匹配的分隔符开始拆分。

Limiting the Number of Substrings starting from the last 3 matched delimiters

查找和替换字符串

在本节中,您将学习两种用于搜索和执行 PowerShell 字符串替换的方法。`Replace()` 方法和 `-Replace` 运算符。

`Replace()` 方法

字符串对象还有一个内置方法,可以帮助执行搜索和替换操作 – `replace()` 方法。`replace()` 方法最多接受四个重载。

`replace()` 方法的可接受重载集如下所示。

<String>.Replace(<original>, <substitute>[, <ignoreCase>][, <culture>])

唯一必需的重载是 `` 和 ``。`` 和 `` 是可选的。

在下面的示例中,代码将查找所有逗号(`,`)字符的实例,并用分号(`;`)替换。

$daysOfTheWeek = 'monday,tuesday,wednesday,thursday,friday,saturday,sunday'
$daysOfTheWeek.Replace(',',';')

除了替换单个字符之外,您还可以使用 `replace()` 方法来搜索和替换字符串。下面的示例代码将单词“day”替换为“night”。

$daysOfTheWeek = 'monday,tuesday,wednesday,thursday,friday,saturday,sunday'
$daysOfTheWeek.Replace('day','NIGHT')
Replacing a matched string using the replace() method

`-Replace` 运算符

替换运算符的语法如下所示。

<string> -replace <original>, <substitute>

使用上述语法,下面的示例代码使用 `-replace` 运算符将单词“day”替换为“Night”。

$daysOfTheWeek = 'monday,tuesday,wednesday,thursday,friday,saturday,sunday'
$daysOfTheWeek -replace 'day','NIGHT'
Replacing a matched character with the -replace operator

这个例子使用了正则表达式匹配来替换字符串,并使用-replace运算符。以下代码搜索here-string中与 (#. ) 匹配的字符串,并将它们替换为nothing

$daysOfTheWeek = @'
1. Line 1
2. Line 2
3. Line 3
4. Line 4
5. Line 5
'@
$daysOfTheWeek -replace "\d.\s",""
Replacing a RegEx match using -replace

从字符串中提取字符串

字符串对象有一个名为SubString()的方法。SubString()方法用于在特定位置从字符串中提取字符串。下面是SubString()方法的语法。

<String>.SubString(<startIndex>[,<length>])

startIndex是指SubString()方法开始搜索的位置索引。length参数表示从startIndex开始返回的字符数。length参数是可选的,如果不使用,则SubString()方法将返回所有字符。

从起始位置和固定长度提取子字符串

下面的示例代码从索引9开始检索$guid字符串值的一部分,并返回后面的5个字符。

$guid = 'e957d74d-fa16-44bc-9d72-4bea54952d8a'
$guid.SubString(9,5)

从动态起始位置提取子字符串

下一个示例演示了如何使用PowerShell字符串长度属性来动态定义起始索引。

以下代码执行以下操作:

  • 获取字符串对象的长度。
  • 通过将长度除以2来获取中间索引的索引位置。
  • 使用中间索引作为子字符串的起始索引。
$guid = 'e957d74d-fa16-44bc-9d72-4bea54952d8a'
$guid.SubString([int]($guid.Length/2))

由于未指定length的值,Substring()方法返回从起始索引开始的所有字符。

Extracting a Substring from a Dynamic Starting Position

比较 PowerShell 字符串

您还可以使用 PowerShell 来比较字符串,使用字符串对象的内置方法,如CompareTo()Equals()Contains()方法。或者,通过使用 PowerShell 的比较运算符

使用 CompareTo() 方法

CompareTo()方法如果两个字符串的值相同则返回0。例如,下面的代码比较两个字符串对象。

$string1 = "This is a string"
$string2 = "This is a string"
$string1.CompareTo($string2)

由于值相同,结果应为0,如下所示。

Using CompareTo() method to compare strings

使用 Equals() 方法和 -eq

Equals()方法和-eq运算符可用于检查两个字符串的值是否相等。

下面的示例使用Equals()方法比较$string1$string2的值。

$string1 = "This is a string"
$string2 = "This is not the same string"
$string1.Equals($string2)

上述代码应返回False,因为$string1$string2的值不相等。

Comparing strings with the Equals() method

下面的示例代码使用-eq而不是来比较$string1$string2的值。

$string1 = "This is a string"
$string2 = "This is not the same string"
$string1 -eq $string2

正如您从以下输出中所见,使用-eqEqual()方法的结果是相同的。

Comparing strings with the -eq operator

使用Contains()方法

在这个例子中,两个字符串被比较,检查PowerShell字符串是否包含另一个字符串的子字符串。

下面的代码显示$string1$string2的值不相等。然而,$string2的值是$string1的一个子字符串。

$string1 = "This is a string 1"
$string2 = "This is a string"
$string1.Contains($string2)

上面的代码的结果应该是True,如下所示。

Comparing strings using the Contains() method

进一步阅读

Source:
https://adamtheautomator.com/powershell-strings/