PowerShell 使用特殊文本命令 -- 字符串操作
格式化操作符 –F 在PowerShell文本操作符中非常重要,经常被用来增强数字类型和日期类型的可读性:
"{0} diskettes per CD" -f (720mb/1.44mb) 500 diskettes per CD
所有的基本操作符形式都大同小异,要处理的数据位于操作符的左右两边,然后通过操作符建立连接。例如,你可以使用下面的语句将文本中指定的字符串替换成目标文本:
“Hello Carl” -replace “Carl”, “Eddie” Hello Eddie
-replace操作符有三种实现方式,其它文本操作符也类似地有三种实现方式,像-replace,-ireplace,-creplace,i前缀表示字符串大小写不敏感(insensitive),c前缀表示字符串大小写敏感(case sensitive)。
#下面的例子没有完成替换,因为当前大小写敏感:
“Hello Carl” -creplace “carl”, “eddie” Hello Carl
第三类i前缀,表示大小写不敏感,和没有前缀的命令逻辑一样(PowerShell中默认的字符串比较是不区分大小写的,所以这里保持一致)。
字符串操作符 |
||
操作符 |
描述 |
示例 |
* |
代表一个字符串 |
“PsTips.Net” -like “*” |
+ |
合并两个字符串 |
“Power” + “Shell” |
-replace,-ireplace |
替换字符串,大小写不敏感 |
“PsTips.Net” -replace “tip”,”1″ |
-creplace |
替换字符串,大小写敏感 |
“PsTips.Net” -replace “Tip”,”1″ |
-eq, -ieq |
验证是否相等,大小写不敏感 |
“Power” -eq “power” |
-ceq |
验证是否相等,大小写敏感 |
“Power” -eq “Power” |
-like, -ilike |
验证字符串包含关系,允许模式匹配,大小写不敏感 |
“PsTips.Net” -like “p*” |
-clike |
验证字符串包含关系,允许模式匹配,大小写敏感 |
“PsTips.Net” – clike “P*” |
-notlike, -inotlike |
验证字符串不包含关系,允许模式匹配,大小写不敏感 |
“PowerShell” -notlike “PS*” |
-cnotlike |
验证字符串不包含关系,允许模式匹配,大小写敏感 |
“PowerShell” -cnotlike “PO*” |
-match,-imatch |
验证模式匹配,大小写不敏感 |
“PowerShell” -match “P*” |
-cmatch |
验证模式匹配,大小写敏感 |
“Hello” -match “[ao]” |
-notmatch, -inotmatch |
验证模式不匹配,大小写不敏感 |
“Hello” -notmatch “[ao]” |
-cnotmatch |
验证模式不匹配,大小写敏感 |
“Hello” -cnotmatch “[ao]” |
PowerShell 使用特殊文本命令 -- 格式化字符串
格式化操作符 –F 能够将一个字符串格式化为指定格式,左边是包含通配符的字符串,右边是待插入和替换的字符串。
“{0} diskettes per CD” -f (720mb/1.44mb) 500 diskettes per CD
-F 右边的表达式必选放在圆括号中,作为一个整体,先进行计算,然后在格式化。否则可能会解析错误:
PS > “{0} diskettes per CD” -f 720mb/1.44mb 数字常量无效: 754974720 diskettes per CD。 所在位置 行:1 字符: 33 + “{0} diskettes per CD” -f 720mb/ <<<< 1.44mb + CategoryInfo : InvalidOperation: (754974720 diskettes per CD:String) [], RuntimeException + FullyQualifiedErrorId : BadNumericConstant
可以在-F的左边放置多个字符串通配符,类似.NET中的String.Format方法。-F右边相应的值或表达式也须要使用逗号分隔。
“{0} {3} at {2}MB fit into one CD at {1}MB” -f (720mb/1.44mb), 720, 1.44, “diskettes” 500 diskettes at 1.44MB fit into one CD at 720MB
PowerShell 使用特殊文本命令 -- 设置数字格式
格式化操作符 -f 可以将数值插入到字符串,每一个通配符都有统一的结构。
{index[,alignment][:format]}:
Index:
索引编号用来识别把那个值用来替换通配符。例如你可能使用了多个通配符,或者同一个通配符使用了多次,甚至多种格式。此时,索引编号是唯一能够识别那个值将用来替换。另外两个选项Alignment和Format则作为辅助条件。
Alignment:
正数和负数,可以指定目标值是否左对齐或者右对齐。还可以支持数值以指定的宽度显示,如果数值的实际宽度大于指定宽度,则忽略指定宽度。如果数值宽度小于指定宽度,剩余的部分会以空白填充,这一选项非常利于制表。
Format:
数值可以被格式化成许多不同的类型,下面会预览这些你可能会用到一些格式概要。
格式化语句比较特殊,大小写敏感,这和PowerShell中其它语句的使用稍有不同。下面举个例子:
# 使用小写字母d:格式化
"Date: {0:d}"
-f
( Get-Date )
Date: 2013/5/31
# 使用大写字母D:格式化
"Date: {0:D}"
-f
( Get-Date )
Date: 2013年5月31
|
符号 |
类型 |
调用示例 |
输入结果 |
# |
数字占位符 |
“{0:(#).##}” -f $value |
(1000000) |
% |
百分号 |
“{0:0%}” -f $value |
100000000% |
, |
千分符 |
“{0:0,0}” -f $value |
1,000,000 |
,. |
一千的整数倍 |
“{0:0,.} ” -f $value |
1000 |
. |
小数点 |
“{0:0.0}” -f $value |
1000000.0 |
0 |
占位符 0 |
“{0:00.0000}” -f $value |
1000000.0000 |
c |
货币 |
“{0:c}” -f $value |
1,000.00 |
d |
十进制 |
“{0:d}” -f $value |
1000000 |
e |
科学计数法 |
“{0:e}” -f $value |
1.000000e+006 |
e |
指数通配符 |
“{0:00e+0}” -f $value |
10e+5 |
f |
保留小数位 |
“{0:f}” -f $value |
1000000.00 |
g |
常规 |
“{0:g}” -f $value |
1000000 |
n |
千分符 |
“{0:n}” -f $value |
1,000,000.00 |
x |
十六进制 |
“0x{0:x4}” -f $value |
0x4240 |
使用上面表格中,你可以快速并舒服地格式化数值,例如千分符的使用可以让用户避免去纠结,1后面到底跟了几个0,是10万呢,还是100万。
另外PowerShell还提供了非常丰富的日期格式化选项,相关的格式见下表。
符号 |
类型 |
调用示例 |
输出 |
d |
短日期格式 |
“{0:d}” –f $value |
2013/6/1 |
D |
长日期格式 |
“{0:D}” –f $value |
2013年6月1日 |
t |
短时间格式 |
“{0:t}” –f $value |
11:18 PM |
T |
长时间格式 |
“{0:T}” –f $value |
23:18:50 |
f |
完整日期和时间(短) |
“{0:f}” –f $value |
2013年6月1日 23:18 |
F |
完整日期和时间(长) |
“{0:F}” –f $value |
2013年6月1日 23:18:50 |
g |
标准时间 (短) |
“{0:g}” –f $value |
2013/6/1 23:18 |
G |
标准时间长 (长) |
“{0:G}” –f $value |
2013/6/1 23:18:50 |
M |
月日格式 |
“{0:M}” –f $value |
6月1日 |
r |
RFC1123 日期格式 |
“{0:r}” –f $value |
Sat, 01 Jun 2013 23:18:50 GMT |
s |
排序日期格式 |
“{0:s}” –f $value |
2013-06-01T23:18:50 |
u |
通用日期格式 |
“{0:u}” –f $value |
2013-06-01 23:18:50Z |
U |
通用排序日期 GMT格式 |
“{0:U}” –f $value |
2013年6月1日 15:18:50 |
Y |
年/月格式模式 |
“{0:Y}” –f $value |
2013年6月 |
自定义日期格式 |
|||
dd |
一个月中天 |
“{0:dd}” -f $value |
01 |
ddd |
星期的缩写 |
“{0:ddd}” -f $value |
周六 |
dddd |
完整星期 |
“{0:dddd}” -f $value |
星期六 |
gg |
纪年法 | “{0:gg}” -f $value |
公元 |
hh |
小时0-12 |
“{0:hh}” -f $value |
11 |
HH |
小时0-23 |
“{0:HH}” -f $value |
23 |
mm |
分钟 |
“{0:mm}” -f $value |
18 |
MM |
月份 |
“{0:MM}” -f $value |
06 |
MMM |
月份缩写 |
“{0:MMM}” -f $value |
六月 |
MMMM |
完整月份 |
“{0:MMMM}” -f $value |
六月 |
ss |
秒 |
“{0:ss}” -f $value |
55 |
tt |
上午或者下午 |
“{0:tt}” -f $value |
下午 |
yy |
两位数字的年份 |
“{0:yy}” -f $value |
13 |
yyyy |
四位数字的年份 |
“{0:yyyy}” -f $value |
2013 |
zz |
不包含分钟的时区 |
“{0:zz}” -f $value |
+08 |
zzz |
包含分钟的时区 | “{0:zzz}” -f $value |
+08:00 |
下面看一个例子:
$date = Get-Date
Foreach
( $format
in
"d" , "D" , "f" , "F" , "g" , "G" , "m" , "r" , "s" , "t" , "T" , `
"u" , "U" , "y" , "dddd, MMMM dd yyyy" , "M/yy" , "dd-MM-yy" ) {
"PowerShell 日期格式, 使用 $format : {0}"
-f
$date .ToString( $format ) }
|
输出:
PowerShell 日期格式,使用 d : 2013/6/6 PowerShell 日期格式,使用 D : 2013年6月6日 PowerShell 日期格式,使用 f : 2013年6月6日 0:13 PowerShell 日期格式,使用 F : 2013年6月6日 0:13:05 PowerShell 日期格式,使用 g : 2013/6/6 0:13 PowerShell 日期格式,使用 G : 2013/6/6 0:13:05 PowerShell 日期格式,使用 m : 6月6日 PowerShell 日期格式,使用 r : Thu, 06 Jun 2013 00:13:05 GMT PowerShell 日期格式,使用 s : 2013-06-06T00:13:05 PowerShell 日期格式,使用 t : 0:13 PowerShell 日期格式,使用 T : 0:13:05 PowerShell 日期格式,使用 u : 2013-06-06 00:13:05Z PowerShell 日期格式,使用 U : 2013年6月5日 16:13:05 PowerShell 日期格式,使用 y : 2013年6月 PowerShell 日期格式,使用 dddd, MMMM dd yyyy : 星期四, 六月 06 2013 PowerShell 日期格式,使用 M/yy : 6/13 PowerShell 日期格式,使用 dd-MM-yy : 06-06-13
如果你想找出那些类型支持被格式化选项,只须查找.NET中那些类型支持多余的ToString()方法.
[appdomain] ::currentdomain.getassemblies() | ForEach-Object
{
$_ .GetExportedTypes() | Where-Object
{! $_ .IsSubclassof( [System.Enum] )}
} | ForEach-Object
{
$Methods
= $_ .getmethods() | Where-Object
{ $_ .name -eq
"tostring" } |%{ "$_" };
If
( $methods
-eq
"System.String ToString(System.String)" ) {
$_ .fullname
}
}
|
输出:
System.Enum System.DateTime System.Byte System.Convert System.Decimal System.Double System.Guid System.Int16 System.Int32 System.Int64 System.IntPtr System.SByte System.Single System.UInt16 System.UInt32 System.UInt64 Microsoft.PowerShell.Commands.MatchInfo
例如,其中的数据类型 ”全球唯一标示符”:
System.Guid
因为你会经常使用到它,它是全球通用的,下面会给你一个简单的例子来创建GUID。
PS > $guid = [GUID]::NewGUID() PS > Foreach ($format in "N","D","B","P") { >> "GUID with $format : {0}" -f $GUID.ToString($format)} >> GUID with N : e1a5d98f4227470b84c2b37a6a8fb894 GUID with D : e1a5d98f-4227-470b-84c2-b37a6a8fb894 GUID with B : {e1a5d98f-4227-470b-84c2-b37a6a8fb894} GUID with P : (e1a5d98f-4227-470b-84c2-b37a6a8fb894)
PowerShell 使用特殊文本命令 -- 固定宽度的制表输出
在一个固定宽度和对齐格式中,显示输出多行文本,要求每一列的输出必选具有固定的宽度。格式化操作符可以设置固定宽度输出。
下面的例子通过DIR返回个目录的中的文件列表,然后通过循环输出,文件名和文件大小,因为文件的名字和大小都是不确定的,长度不一样,所以结果拥挤粗糙,可读性差。
PS > dir | ForEach-Object { "$($_.name) = $($_.Length) Bytes" } .android = Bytes .VirtualBox = Bytes CMB = Bytes Contacts = Bytes Desktop = Bytes Documents = Bytes Downloads = Bytes Favorites = Bytes funshion = Bytes Links = Bytes Podcasts = Bytes Roaming = Bytes Saved Games = Bytes Searches = Bytes SkyDrive = Bytes Tracing = Bytes Virtual Machines = Bytes VirtualBox VMs = Bytes a = 12022 Bytes a.csv = 986 Bytes a.ps1 = 18 Bytes a.txt = 946 Bytes funshion.ini = 6798 Bytes PUTTY.RND = 600 Bytes
下面固定列宽的结果,就显得可读性强了。要设置列宽可以将一个逗号放置在通配符与列宽编号的中间,负数设置左对齐{0,-20},左对齐20个字符,取第一个返回值,正数设置右对齐{1,10},右对齐10个字符,取第二个返回值。
PS> dir | ForEach-Object { "{0,-20} = {1,10} Bytes" -f $_.name, $_.Length } Virtual Machines = Bytes VirtualBox VMs = Bytes a = 12022 Bytes a.csv = 986 Bytes a.ps1 = 18 Bytes a.txt = 946 Bytes funshion.ini = 6798 Bytes PUTTY.RND = 600 Bytes .....
PowerShell 使用特殊文本命令 -- string 对象方法
从之前的章节中,我们知道PowerShell将一切存储在对象中,那这些对象中包含了一系列中的称之为方法的指令。默认文本存储在String对象中,它包含了许多非常有用的处理文本的命令。例如,要确定一个文件的扩展名,可以使用LastIndexOf()获取最后一个字符“.”的位置,继续使用Substring()获取扩展名子串。
PS> $path = "C:\prefs.js" PS> $path.Substring( $path.LastIndexOf(".")+1 ) Js
另外一条途径,使用Split方法,对文件的完整名称进行分割,得到一个字符串数组,取最后一个元素,PowerShell中可以通过索引-1来获取数组中最后一个元素。
PS> $path.Split(".")[-1] Js
下面的表格会给出String对象的所有方法:
函数 | 描述 | 示例 |
CompareTo() | 与另一个字符串比较 | (“Hello”).CompareTo(“Hello”) |
Contains() | 是否包含制定子串 | (“Hello”).Contains(“ll”) |
CopyTo() | 拷贝子串至新字符串中 | $a = (“HelloWorld”).toCharArray()(“User!”).CopyTo(0,
$a, 6, 5)$a |
EndsWith() | 是否以制定子串结尾 | (“Hello”).EndsWith(“lo”) |
Equals() | 是否与另一个字符串相同 | (“Hello”).Equals($a) |
IndexOf() | 返回第一次匹配的所索引 | (“Hello”).IndexOf(“l”) |
IndexOfAny() | 返回字符串中任意字符的首次匹配索引 | (“Hello”).IndexOfAny(“loe”) |
Insert() | 在指定位置插入字符串 | (“HelloWorld”).Insert(6,”brave “) |
GetEnumerator() | 枚举字符串中所有字符 | (“Hello”).GetEnumerator() |
LastIndexOf() | 字符的最后匹配位置 | (“Hello”).LastIndexOf(“l”) |
LastIndexOfAny() | 任意字符的最后匹配位置 | (“Hello”).LastIndexOfAny(“loe”) |
PadLeft() | 左边补齐空白是字符串至指定长度 | (“Hello”).PadLeft(10) |
PadRight() | 右边填充空白是字符串至指定长度 | (“Hello”).PadRight(10) + “World!” |
Remove() | 从指定位置开始移除指定长度 | (“PsTips”).Remove(2,2) |
Replace() | 替换指定字符串 | (“PsTips”).replace(“Ps”,”PS1″) |
Split() | 以指定分隔符切割字符串 | (“HelloWorld”).Split(“l”) |
StartsWith() | 是否以指定子串开始 | (“HelloWorld”).StartsWith(“He”) |
Substring() | 从指定位置取指定长度子串 | “HelloWorld”).Substring(4,3) |
ToCharArray() | 转换成字符数组 | (“HelloWorld”).toCharArray() |
ToLower() | 转换成小写 | (“HelloWorld”).toLower() |
ToLowerInvariant
() |
以区域规则转换成小写 | (“HelloWorld”).ToUpperInvariant() |
ToUpper() | 转换成大写 | (“HelloWorld”).ToUpper() |
ToUpperInvariant
() |
以区域规则转换成大写 | (“HelloWorld”).ToUpperInvariant
() |
Trim() | 移除字符串前后空格 | (” HelloWorld “). Trim() |
TrimEnd() | 移除字符串结尾的空格 | (“HelloWorld “). TrimEnd() |
TrimStart() | 移除字符串开始的空格 | (” HelloWorld”). TrimStart() |
Chars() | 返回指定位置的字符 | (“Hello”).Chars(0) |
以Split()为例来分析方法
在之前的章节中,我们已经知道可以通过Get-Member来查看一个对象中包含了那些可以被调用的方法。正好最为一个简单的回顾,来查看Split的定义。
PS C:\> ("Pstips.net" | Get-Member Split).definition string[] Split(Params char[] separator), string[] Split(char[] separator, int count), string[] Split(char[] separator, System.StringSplitOptions options), string[] Split(char[] separator, int count, System.StringSplitOptions options), string[] Split(string[] separator, System.StringSplitOptions options), string[] Split(string[] sepa rator, int count, System.StringSplitOptions options)
Define属性可以获取方法参数定义,但是可读性比较坑爹。我们仍然用上面表格中的Replace方法,将分隔符稍作替换,即可增强可读性。
PS C:\> ("Pstips.net" | Get-Member Split).definition.Replace("), ", ")`n") string[] Split(Params char[] separator) string[] Split(char[] separator, int count) string[] Split(char[] separator, System.StringSplitOptions options) string[] Split(char[] separator, int count, System.StringSplitOptions options) string[] Split(string[] separator, System.StringSplitOptions options) string[] Split(string[] separator, int count, System.StringSplitOptions options)
之前说过反引号,类似高级语言中的转义符反斜杠。
从上面的输出可以发现Split有6种不同的调用方法,而之前可能更多的只使用过一个参数的方法。PowerShell在处理文本时,可能会碰到多个分隔符,而Split方法调用只须一次即可。
PS C:\> "http://www.pstips.net".split(":./") http www pstips net
中间有空白,咋整,能移除吗,StringSplitOptions轻装上阵:
PS C:\> "http://www.pstips.net".split(":./",[StringSplitOptions]::RemoveEmptyEntries) http www pstips net
之前有一个小算法题,移除字符串中相邻的重复的空格。在不考虑效率的前提下,可以使用Split先分割,分割后再将得到的元素以指定分隔符拼接。但是拼接用到的Join方法,并不属于string对象,而属于String类,也正是下面要讲的。
PowerShell 使用特殊文本命令 -- string 类方法
使用String类命令:
之前已经讨论过,对象方法和类方法的区别了,再回顾一次。String对象衍生自string类
在控制台输入[String]::然后按Tab键会自动智能提示,这些方法就是String类命令。
Get-Member会返回所有string对象的方法,可以通过参数只返回静态方法,也就是string类命令。使用几率最高的自然Format方法,但是因为PowerShell中已经有了大书特书的-F操作符了,Format方法可以秒杀了。但是Join和Contac还是可以聊聊的。
Join()方法曾经在上一部分演示Split()提到过,它可以将一个数组或者列表字符串合以指定分隔符并成一个字符串。例如自定义一个函数,移除多余的白空格。
1
2
3
4
5
|
function
RemoveSpace( [string] $text ) {
$private:array
= $text .Split( " " , `
[StringSplitOptions] ::RemoveEmptyEntries)
[string] ::Join( " " , $array )
}
|
PS C:\> RemoveSpace("PowerShell 中文博客的网址为 :http://www.pstips.net") PowerShell 中文博客的网址为 :http://www.pstips.net
Concat()将多个字符串拼接成一个字符串。
Concat()工作起来类似字符串操作符“+”,类似而已,总有区别。
PS C:\> "Hello" + " " + "World!" Hello World!
区别在于第一个左表达式必选是一个String类型,否则,麻烦来了:
PS C:\> (Get-Date) + "PStips.Net" 无法将“op_Addition”的参数“1”(其值为“PStips.Net”)转换为类型“System.TimeSpan”:“无法将值“PStips.Net”转换为类型“System.TimeSpan”。错误:“字符串未被识别为有效 的 TimeSpan。”” 所在位置 行:1 字符: 13 + (Get-Date) + <<<< "PStips.Net" + CategoryInfo : NotSpecified: (:) [], MethodException + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
此时可以使用:
PS C:\> ""+(Get-Date) + "PStips.Net" 06/04/2013 00:54:27PStips.Net
或者:
PS C:\> [string]::Concat((Get-Date),"PStips.Net") 2013/6/4 0:55:00PStips.Net
PowerShell 使用特殊文本命令 -- 简单模式匹配
在验证用户的条目时,模式识别是必要并且常见的任务。例如判断用户的输入的字符串是否是一个合法的网络IP地址,或者电子邮箱。有用并且高效的模式匹配需要一些能代表确切数字和字符的通配符。
许多年前,人们就发明了简单的模式匹配,一直沿用至今。
1
2
3
4
5
6
7
8
|
#列出当前目录中的文本文件
Dir *.txt
# 列出系统目录中以‘n’或‘w’打头的文件
dir $env:windir \ [nw] *.*
# 列出文件后缀名以‘t’打头,并且后缀名只有三个字符的文件
Dir *.t??
# 列出文件中包含一个’e’到’z’之间任意字符的文件
dir *[e-z].*
|
通配符 | 描述 | 示例 |
* | 任意个任意字符,(包含零个字符) | Dir *.txt |
? | 一个任意字符 | Dir *.??t |
[xyz] | 一个包含在指定枚举集合中的字符 | Dir [abc]*.* |
[x-z] | 一个包含在指定区间集合中的字符 | Dir *[p-z].* |
上面表格中的通配符主要被使用在文件系统中,但是在字符串操作符-like和-notlike 中也可以。例如通过下面的方式可以简单验证IP地址。
1
2
|
$ip
= Read-Host
"IP address"
If
( $ip
-like
"*.*.*.*" ) { "valid"
} Else
{ "invalid"
}
|
也可以简单验证电子邮件地址。
1
2
|
$email
= ".@."
$email
-like
"*.*@*.*"
|
然而上面的例子也仅能验证一些低级错误,还不是很确切。例如a.b.c.d不是一个有效的IP地址,但是上面的模式匹配却能通过验证。
参考:
http://www.pstips.net/powershell-online-tutorials/