1. 程式人生 > 其它 >PowerShell命令與指令碼(12)——文字和正則表示式

PowerShell命令與指令碼(12)——文字和正則表示式

PowerShell定義文字

使用引號可以定義字串,如果想讓自己定義的字串原樣輸出,可以使用單引號。 如果想讓自己的定義的字元中的變數被內容替換,表示式被執行可以使用雙引號. 1、文字中的特殊字元 如果文字放置在一個閉合的雙引號中,Powershell直譯器會去尋找特殊字元.在這方便主要有兩種特殊字元,一個是變數的字首“$”,一個是反引號“`”位於數字鍵1左邊。 處理變數 將變數放在字串中,輸出時變數會被替換成變數本身的值或者內容。如果將表示式放置在字串中,並且使用的格式如“$(expression)”,表示式也會被執行,並被替換成表示式執行的輸出。 Powershell轉義字元 在其它程式語言中喜歡將反斜槓作為轉義字元,但是在Powershell中扮演轉義字元角色的不是反斜槓,而是反引號“`”字串中的反引號,會對緊跟隨其後的字元進行特殊處理。例如下面的,在一個字串中輸出雙引號,和換行符。 其它的轉義字元如下表
Powershell轉義字元表
轉義字元 描述
`n 換行符
`r 回車符
`t 製表符
`a 響鈴符
`b 退格符
`’ 單引號
`” 雙引號
`0 Null
反引號本身
2、Here strings 定義多行文字 @“字串”@格式定義多行文字,尤其是較長的文字,再好不過了 這裡要注意開始和結束的標記必須另起一行。 3、使用者互動 如果要提示使用者輸入可以使用read-host 只是有一點Read-Host儲存的字串使用的單引號閉合,也就是說不會自動解析變數,不過可以通過ExpandString方法解析,例如: 但是如果想通過Read-Host接受敏感資料,比如密碼,可以使用-asSecureString選項,不過這樣讀取到的資料為SecureString,及為加過密後的資料,當然你可以將密碼轉換成普通文字. 詢問使用者名稱和密碼
如果你想授權一個使用者需要提供使用者憑據,可以使用Get-Credential命令,該命令會彈出一個安全對話方塊,一旦使用者輸入完畢,就會返回一個Credential物件包含使用者名稱和密碼

使用特殊文字命令

1. 字串操作符

1、格式化字串 格式化操作符 –F 能夠將一個字串格式化為指定格式,左邊是包含萬用字元的字串,右邊是待插入和替換的字串。 -F 右邊的表示式必選放在圓括號中,作為一個整體,先進行計算,然後在格式化。否則可能會解析錯誤: 可以在-F的左邊放置多個字串萬用字元,類似.NET中的String.Format方法。-F右邊相應的值或表示式也須要使用逗號分隔。 所有的基本操作符形式都大同小異,要處理的資料位於操作符的左右兩邊,然後通過操作符建立連線。例如,你可以使用下面的語句將文字中指定的字串替換成目標文字: -replace操作符有三種實現方式,其它文字操作符也類似地有三種實現方式,像-replace
-ireplace-creplace,i字首表示字串大小寫不敏感(insensitive),c字首表示字串大小寫敏感(case sensitive)。 #下面的例子沒有完成替換,因為當前大小寫敏感: 第三類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]”
2、設定數值格式 格式化操作符 -f 可以將數值插入到字串,每一個萬用字元都有統一的結構。 {index[,alignment][:format]}:
  • Index:
索引編號用來識別把那個值用來替換萬用字元。例如你可能使用了多個萬用字元,或者同一個萬用字元使用了多次,甚至多種格式。此時,索引編號是唯一能夠識別那個值將用來替換。另外兩個選項Alignment和Format則作為輔助條件。
  • Alignment:
正數和負數,可以指定目標值是否左對齊或者右對齊。還可以支援數值以指定的寬度顯示,如果數值的實際寬度大於指定寬度,則忽略指定寬度。如果數值寬度小於指定寬度,剩餘的部分會以空白填充,這一選項非常利於製表。
  • Format:
數值可以被格式化成許多不同的型別,下面會預覽這些你可能會用到一些格式概要。 格式化語句比較特殊,大小寫敏感,這和PowerShell中其它語句的使用稍有不同。下面舉個例子:
符號 型別 呼叫示例 輸入結果
# 數字佔位符 “{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 “{0:t}” –f $value
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
下面看一個例子: 如果你想找出那些型別支援被格式化選項,只須查詢.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.Guid 因為你會經常使用到它,它是全球通用的,下面會給你一個簡單的例子來建立GUID。
擴充套件:GUID(全域性唯一識別符號) 全域性唯一識別符號(GUID,Globally Unique Identifier)是一種由演算法生成的二進位制長度為128位的數字識別符號。GUID主要用於在擁有多個節點、多臺計算機的網路或系統中。在理想情況下,任何計算機和計算機叢集都不會生成兩個相同的GUID。GUID 的總數達到了2^128(3.4×10^38)個,所以隨機生成兩個相同GUID的可能性非常小,但並不為0。所以,用於生成GUID的演算法通常都加入了非隨機的引數(如時間),以保證這種重複的情況不會發生。
3、固定寬度的製表輸出 在一個固定寬度和對齊格式中,顯示輸出多行文字,要求每一列的輸出必選具有固定的寬度。格式化操作符可以設定固定寬度輸出。 下面的例子通過DIR返回個目錄的中的檔案列表,然後通過迴圈輸出,檔名和檔案大小,因為檔案的名字和大小都是不確定的,長度不一樣,所以結果擁擠粗糙,可讀性差。 下面固定列寬的結果,就顯得可讀性強了。要設定列寬可以將一個逗號放置在萬用字元與列寬編號的中間,負數設定右對齊,正數設定左對齊。

2. PowerShell String物件方法

從之前的章節中,我們知道PowerShell將一切儲存在物件中,那這些物件中包含了一系列中的稱之為方法的指令。預設文字儲存在String物件中,它包含了許多非常有用的處理文字的命令。例如,要確定一個檔案的副檔名,可以使用LastIndexOf()獲取最後一個字元“.”的位置,繼續使用Substring()獲取副檔名子串。 另外一條途徑,使用Split方法,對檔案的完整名稱進行分割,得到一個字串陣列,取最後一個元素,PowerShell中可以通過索引-1來獲取陣列中最後一個元素。 下面的表格會給出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的定義。 ("Pstips.net" | Get-Member Split).definition Define屬性可以獲取方法引數定義,但是可讀性比較坑爹。我們仍然用上面表格中的Replace方法,將分隔符稍作替換,即可增強可讀性。 之前說過反引號,類似高階語言中的轉義符反斜槓。 從上面的輸出可以發現Split有6種不同的呼叫方法,而之前可能更多的只使用過一個引數的方法。PowerShell在處理文字時,可能會碰到多個分隔符,而Split方法呼叫只須一次即可。 中間有空白,咋整,能移除嗎,StringSplitOptions輕裝上陣: "https://www.baidu.com".Split(":./",[System.StringSplitOptions]::RemoveEmptyEntries) 之前有一個小演算法題,移除字串中相鄰的重複的空格。在不考慮效率的前提下,可以使用Split先分割,分割後再將得到的元素以指定分隔符拼接。但是拼接用到的Join方法,並不屬於string物件,而屬於String類,也正是下面要講的。

3. PowerShell String類方法

使用String類命令: 之前已經討論過,物件方法和類方法的區別了,再回顧一次。 String物件衍生自string類在控制檯輸入[String]::然後按Tab鍵會自動智慧提示,這些方法就是String類命令。 Get-Member會返回所有string物件的方法,可以通過引數只返回靜態方法,也就是string類命令。使用機率最高的自然Format方法,但是因為PowerShell中已經有了大書特書的-F操作符了,Format方法可以秒殺了。但是Join和Contac還是可以聊聊的。 Join()方法曾經在上一部分演示Split()提到過,它可以將一個數組或者列表字串合以指定分隔符併成一個字串。例如自定義一個函式,移除多餘的白空格。
function RemoveSpace([string]$text){
$Private:array=$text.Split(" ",[System.StringSplitOptions]::RemoveEmptyEntries)
[string]::Join(" ",$array)
}
Concat()將多個字串拼接成一個字串。 Concat()工作起來類似字串操作符“+”,類似而已,總有區別。 區別在於第一個左表示式必選是一個String型別,否則,麻煩來了: 此時可以使用: 或者:

簡單模式匹配

在驗證使用者的條目時,模式識別是必要並且常見的任務。例如判斷使用者的輸入的字串是否是一個合法的網路IP地址,或者電子郵箱。有用並且高效的模式匹配需要一些能代表確切數字和字元的萬用字元。 許多年前,人們就發明了簡單的模式匹配,一直沿用至今。
#列出當前目錄中的文字檔案
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地址。
$ip = Read-Host "IP address"
If ($ip -like "*.*.*.*") { "valid" } Else { "invalid" }
也可以簡單驗證電子郵件地址。
$email = ".@."
$email -like "*.*@*.*"
然而上面的例子也僅能驗證一些低階錯誤,還不是很確切。例如a.b.c.d不是一個有效的IP地址,但是上面的模式匹配卻能通過驗證。

正則表示式

1. 定義模式

如果你需要更加精確的模式識別需要使用正則表示式。正則表示式提供了更加豐富的萬用字元。正因為如此,它可以更加詳細的描述模式,正則表示式也因此稍顯複雜。 使用下面的表格中列出的正則表示式元素,你可以非常精準的描述模式。這些正則表示式元素可以歸為三大類。 字元:字元可以代表一個單獨的字元,或者一個字元集合構成的字串。 限定符:允許你在模式中決定字元或者字串出現的頻率。 定位符:允許你決定模式是否是一個獨立的單詞,或者出現的位置必須在句子的開頭還是結尾。 正則表示式代表的模式一般由四種不同型別的字元構成。 文字字元:像”abc”確切地匹配”abc“字串 轉義字元:一些特殊的字元例如反斜槓,中括號,小括號在正則表示式中居於特殊的意義,所以如果要專門識別這些特殊字元需要轉義字元反斜槓。就像”\[abc\]”可以識別”[abc]”。 預定義字元:這類字元類似佔位符可以識別某一類字元。例如”\d”可以識別0-9的數字。 自定義萬用字元:包含在中括號中的萬用字元。例如”[a-d]”識別a,b,c,d之間的任意字元,如果要排除這些字元,可以使用”[^a-d]”。
元素 描述
. 匹配除了換行符以外的任意字元
[^abc] 匹配除了包含在中括號的任意字元
[^a-z] 匹配除了包含在中括號指定區間字元的任意字元
[abc] 匹配括號中指定的任意一個字元
[a-z] 匹配括號中指定的任意區間中的任意一個字元
\a 響鈴字元(ASCII 7)
\c or \C 匹配ASCII中的控制字元,例如Ctrl+C
\d 匹配數字字元,等同於[0-9]
\D 匹配數字以外的字元
\e Esc (ASCII 9)
\f 換頁符(ASCII 15)
\n 換行符
\r 回車符
\s 白空格(空格,製表符,新行)
\S 匹配白空格(空格,製表符,新行)以外的字元
\t 製表符
\uFFFF 匹配Unicode字元的十六進位制程式碼FFFF。例如,歐元符號的程式碼20AC
\v 匹配縱向製表符(ASCII 11)
\w 匹配字元,數字和下劃線
\W 匹配匹配字元,數字和下劃線以外的字元
\xnn 匹配特殊字元,nn代表十六進位制的ASCII碼
.* 匹配任意數量的字元(包括0個字元)
限定符 上面表格中列出的每個萬用字元,可以代表一個確定的字元。使用限定符,可以精確地確定字元的出現頻率。例如”\d{1,3}”代表一個數字字元出現1到3次。
元素 描述
* 匹配一個元素0次或者多次(最大限度地匹配)
*? 匹配前面的元素零次或者多次(最小限度地匹配)
.* 匹配任意個數的任意字元(包括0個字元)
? 匹配上一個元素0次或者1次(最大限度地匹配)
?? 匹配上一個元素0次或者1次(最小限度地匹配)
{n,} 匹配上一個元素至少n次
{n,m} 匹配上一個元素n至m次
{n} 匹配上一個元素n次
+ 匹配上一個元素一次或者多次
識別IP地址 類似IP地址的模式通過正則表示式來描述比簡單的萬用字元字元會更加精確。通常會使用字元和量詞結合,來指定某個具體的字元應當出現,以及出現的頻率:
元素 描述
$ 在字串的結尾匹配
\A 在字串的開始匹配(包含多行文字)
\b 在單詞的邊界匹配
\B 不在單詞的邊界匹配
\Z 在字串的結尾匹配(包含多行文字)
^ 在字串的開始匹配
$parttern="\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" 這裡模式被描述成4個類似的數字,每個數字以圓句句號分割,每個數字的位數介於1-3。另外在開始和結尾可以包含空格。當這些數字處於0到255之間時,IP的驗證還是挺完美的。 但是當某個數字超過255時,則顯得無能為力。 驗證Email格式 如果你想驗證使用者提供的E-Mail地址是不是一個合法電子郵件格式,可以使用下面的正則表示式: $parttern = "\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b" 無論什麼時候,希望一個表示式以一個單獨的“單詞”在文字中出現,可以使用分隔符:單詞邊界(定位符”\b”),這樣正則表示式就會知道你感興趣的是字串中除去那些白空格(像空格,製表符,換行符)以外的字元。 緊隨其後的正則表示式指定的是那些字元可以被允許出現在電子郵件地址中。被允許的字元放在方括號中,由字元區間(例如:A-Z0-9″)和單個字元(例如:”._%+-“)構成。“+”放在方括號後面是一個限定符,意味著前面的字元至少出現一次。當然你可以規定出現更多的字元。 接下來的是“@”,@之後的字元可以和@前面的一樣。在電子郵件地址後面必須出現一個圓句點。但是因為圓句點屬於特殊字元,所以加了反斜槓轉義,讓它以普通字元的形式出現在正則表示式中。 在圓句點之後是域標識,它們完成由字母([A-Z])組成,限定符({2,4})緊隨其後指定域識別符號應當至少由2個字元,至多由4個字元組成。 但是上面的正則表示式仍舊有一些瑕疵: $parttern = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$"

2. 同時搜尋不同的詞語

有時搜尋的詞語比較含糊不清,因為這些詞語可能有多種寫法。你可以使用限定符“?”來標記這些詞語作為可選字元。非常簡單,把“?”放在可選字元後面即可。這樣“?”前的字元就變成了可選字元,而不是非得出現。 注意,此處的字元“?”並不代表任何字元,因為怕你可能會聯想到簡單模式匹配裡面的“?”。正則表示式中的“?”,只是一個限定符,它代表的是指定字元或者子表示式出現的頻率。具體到上面的例子,“u?”就確保了字元“u”在模式中不是必需的。常用的其它限定符,還有“*”(出現0次後者多次)和“+”(至少出現一次)。 如果你想標記更多的連續字元作為可選,可以把這些字元放置圓括號中建立子表示式。下面的子表達可以同時識別“Nov”和“November”: 如果你想使用多個可選的搜尋詞語,可以使用“或”操作符“|”: 如果你想將搜尋的詞語和固定文字結合在一起,作為可選,仍然可以使用子表示式:

3. 大小寫敏感

為了和PowerShell的習慣保持一致,操作符-match是大小寫不敏感的,如果你想切換至大小寫敏感的操作符可以使用“-cmatch” 如果你只想在模式的部分片段中使用大小寫敏感,仍舊可以使用-match,但是可以在正則表示式中指定部分模式是不是大小寫敏感。跟在“(?i)”結構後的字元大小寫不敏感,跟在(?-i)結構後面的字元大小寫敏感。下面的例子會演示這個區別,模式中的字元字串 “st”因為被(?-i)標記為大小寫敏感,所以可以匹配“TEst”,但不能匹配“TEST”。 但是如果你使用的是.NET framework的物件RegEx,它可以自動的在大小寫敏感與不敏感之間切換。既可以使用IgnoreCase引數來顯示的指定,也可以在模式中使用上面提到的結構來指定。 [regex]::matches("test", "TEST", "IgnoreCase")

4. 文字中搜索資訊

正則表示式可以識別模式。它們也可以根據確定的模式從文字中過濾出資料,因此正則表示式是用來處理源文字的一款非常優秀的工具。 例如,你想從一封郵件中過濾出一個確切的電子郵件地址,就可以使用我們之前提到過正則表示式。然後就可以在變數$matches找出返回的結果。在你使用-match操作符時,$matches變數會自動被建立,並存儲過濾出的結果。$matches是一個雜湊表,你既可以輸出一個完整的雜湊表,也可以使用在中括號中的名稱(鍵值)逐個訪問其中的某個元素。 如果文字中有多個電子郵件,上面的方法還會有效嗎?非常遺憾,它不會這樣做。操作符-match只會匹配一次正則表示式。因此如果你想在源文字中搜索多個出現的模式,你必須切換至RegEx物件,值得一提的是RegEx物件不像-match,Regex物件預設是大小寫敏感的,你要想大小寫不敏感,可以參考前面的文章。

5. 搜尋不同的關鍵字

你可以使用間隔結構“|”來搜尋某一組關鍵字,然後找出那些實際上出現的關鍵字: $matches會告訴你那些關鍵字實際上在字串上出現了。但是要注意正則表示式中關鍵字的順序。是因為第一個匹配到的關鍵字會被選中決定的。所以接下來的例項,結果感覺不正確: 所以接下來更改關鍵字的順序可以讓較長的關鍵字被選中。 或者,你可以更加精確地定製你的正則表示式,記住你實際上搜索的是一個獨立的單詞。所以在關鍵字中加入單詞邊界,讓順序的影響失效。 也確實這樣,-match只會搜尋第一次匹配,如果你的源文字中可能須要和包含關鍵字的多次出現,可以重新使用RegEx 上面的例子使用了.NET中的原始正則表示式類。

6. 組

一串原始的文字行通常有大量有用資訊,你可以使用子表示式來收集資料,可以在之後單獨使用。基本的規則是所有想通過模式來搜尋的資料應當放在圓括號中,因為變數$matches會將這些子表示式以單獨的序列返回。如果文字行首先包含了資料,然後是其它文字,兩者之間以製表符分割,你可以如下描述這段模式: 當使用子表示式時,$matches會包含所有搜尋模式,陣列的第一個元素命名為“0”,子表示式分別位於兩個圓括號中,為了使他們更加便於讀取理解,你可以分配給每個子表示式它們自己的名子(鍵),接下來通過它們去呼叫匹配的結果。給子表示式命名,可以在圓括號中輸入type ?。 每個子表示式檢索的結果都需要儲存空間,如果特定場合中不需要這些結果可以,可以丟棄它們,因為這樣可以提高正則表示式匹配的速度。要丟棄結果,可以在子表示式中的第一個語句上加上“?:

7. 深入使用子表示式

借住子表示式的幫助,你可以創建出更加驚人和靈活的正則表示式。例如,怎樣定義一個網站中HTML標籤的模式呢?一個標籤通常包含同樣的結構:<tagname [parameter]>…</tagname>,這就意味著可以快速定義出一個非常嚴格的HTML標籤模式: 模式以固定的文字”<body “開始,額外的字元以單詞為界。接下來跟著右括號”>”,”>”之後則是中的內容,這些內容可以由任意數量的字元(.*?)組成。圓括號中是一個子表示式,會在$matches中返回檢索到的中的結果。結尾的部分為固定文字 “”)開始,另外一次以(“”)終結。如果一個正則表示式支援處理任意標籤,那它必須能夠自動地找出所有的標籤,並且在前後兩個位置都能使用。怎樣完成它呢?像這樣: 上面的正則表示式不在包含預定義的固定HTML 標籤,卻能匹配所有的HTML標籤。它是如何辦到的呢?因為初始標籤被定義成子表示式,該子表示式以字母開始,可以由任意字母或數字組成。 ([A-Z][A-Z0-9]*) 在開始匹配到的標籤必須在之後也能迭代匹配到,就是要有頭也得有尾,善始善終。此處你會發現引入了一個新寫法””,“\1”引用的是第一個子表示式。這樣就保證了HTML標籤開始的和結尾的一致了。

8. 貪婪與非貪婪匹配

根據正則表示式的規則,讀者可能會懷疑在匹配HTML標籤時,使用的事“.*?”而不是簡單的“.*”。畢竟“.*”已經可以匹配足夠的字元了。“.*”和“.*?”之間的不同並不容易識別。下面通過一個例子來澄清。 假設你要再一個長檔案中匹配英文月份,但是月份並不是以同樣的方式出現的。有時使用短格式,有時使用長格式。正如接下來看見的一樣,正則表示式完成可以做到。因為正則表示式支援子表示式以可選的形式出現。 上面兩種情況正則表示式都能識別月份,但是返回的結果卻不相同,一個是Feb,一個是February。預設,正則表示式屬於“貪婪”模式。在搜尋到Feb後會繼續貪婪地搜尋更多符合模式的的字元。如果可以整個文字會返回。 然後,如果你主要關心的只是規範的月份名稱,你可能更喜歡獲取縮寫的月份名稱。這也正是“??”限定符做的,它會將正則表示式轉換成“非貪婪”模式,一旦他識別到一個模式,就會立即返回,不再會檢查可選的子表示式是否匹配。 到底限定符“??”和之前的例子中的限定符“*?”有什麼聯絡呢?事實上“*?”不是一個獨立量詞。它會將“貪婪”模式轉換成“非貪婪”模式。這就意味著,你可以使用“?”強制將限定符“*”轉換成非貪婪模式,儘可能返回短結果。

9. 搜尋字元片段

舉一個例子演示怎樣通過正則表示式輕鬆的搜尋字串片段。下面會匹配位於兩個特定單詞中的字串,並且字元的長度介於1到6之間。

10. 替換字串

之前介紹過-replace操作符,你可以能已經知道了怎樣替換字串中的字串。讓我們來回顧一下: 但是這種簡單的替換不可能永遠都是高效的,因此可以嘗試使用正則表示式來完成替換工作。下面有一個好玩的例子,用來演示它怎樣實用。 也許你會碰到將多個類似的詞語替換成同一個詞語這樣的需求。如果沒有正則表示式,需要重複使用replace操作符多次。而每一次replace都會伴隨一次遍歷,效率明顯很低。取而代之,如果使用正則表示式,則非常方便。 你可以在括號中輸入任意的詞語,多個詞語之間用“|”隔開,這樣所有的詞語都會被指定的字串替換掉。

11. 使用反向引用

最後一個例子在一個字串中替換了多個指定的關鍵字。通常效率還是挺高的,但是有時候你可能不想替換所有出現的關鍵字,而只是想替換出現在特殊上下文中的關鍵字。這樣的情況下,上下文必須定義在模式中。例如,怎樣更改正則表示式,讓它只替換名字Miller和Meyer. 輸出結果看起來有點奇怪,但是確實是和搜尋模式匹配的。被替換掉的僅僅是Mr.或者Mrs. Miller和Mr. 或者 Mrs. Meyer。詞語”Mr. Werner”沒有被替換。遺憾的是結果沒道理替換掉整個模式,至少人名應當保留。這可能嗎? 此時反向引用應當登場了。在正則表示式中,不論你什麼時候使用圓括號,圓括號中的結果都是分開被評估的。你可以在你的“替換串”中使用這些分離出來的結果。第一個子表示式的結果總是”Mr.” 或者 “Mrs.”。第二個子表示式總是返回人名。詞語”$1” 和 “$2″在“替換串”中提供了你的子表示式(因此,數字是一串連續的數字;對於補充的子表示式你可以使用”$3″)。 奇怪的是,第一個反向引用似乎並沒有工作。當然原因也非常明顯: “$1” and “$2″看起來是PowerShell 變數, 但是實際上它們應當是操作符-replace的正則表示式詞語。導致此結果的是你把“替換串”放在了雙引號中了,PowerShell會將變數替換成具體的值,而這個值一般情況下應當為空。所以要是反向引用在“替換串”中起作用,你必須將“替換串”放置在單引號中,這樣讓$變成普通字元,這樣PowerShell就不會把它識別為自己的變量了,並完成替換功能:

12. 在文字中插入字元

“替換串”可以由多行文字中的多個例項組成。例如,在你平時回覆一封郵件時,你可能在新郵件中會通過在行首新增 “>” 符號來引用原郵件的中的內容。正則表示式就可以做這樣的標記。 然而,要完成它,你可能得稍微瞭解一點“多行”模式。通常,該模式是關閉的,此時限定符”^”代表文字的開始,”$”代表文字的結束。要讓這兩個限定符可以代表文字行的開始和文字行的結束,必須使用”(?m)”來開啟“多行”模式。只有這樣,–replace 才會在每個單獨的文字行之間替換模式。在“多行”模式開啟後,限定符”^” 和 “\A”,還有”$” and “\Z”會頓時擁有不同的表現。”\A”仍然會標誌文字的開始,而”^”則會標誌文字行的開始。”\Z”仍然會標誌文字的結尾,而”$”則會標誌文字行結尾。

13. 刪除多餘的空格

使用正則表示式可以完成一些日常任務,比如一處一個字串中多餘的白空格。模式需要描述一個空格(字元:“\s”)至少出現兩次(限定符:“{2,}”)。然後以一個正常的單空格字元替換。 "太多 太多的 空格 怎麼才能減少 " -replace "\s{2,}" ," "

14. 搜尋和移除重複的單詞

怎樣才能移除文字中多餘的單詞。這裡,仍舊可以再次使用空格。模式可以這樣定義: "\b(\w+)(\s+\1){1,}\b" 模式會搜尋一個單詞(以“\b”定位),它由一個單片語成(字元“\w” 和限定符“+”),白空格緊隨以後(字元“\s”和限定符“?”)。該模式中,白空格字元和將要被替換的單詞必須至少出現一次(至少一次或者更多次,使用限定符“{1,}”)。整個模式會被第一次出現的反向引用給替換掉,也就是位於第一個的單詞。

15. 非捕獲組

(expression) 是一種簡單的子表示式 (?:expression)是一種特殊的子表示式 後者不會將子表示式的匹配結果加入組中

文字處理例項

(一) 問題描述: 有如下一段文字檔案,開頭有許多描述,字元“~”為有用資料的開始標誌,要求:求所有電阻值的個數,平均值,總和,最大值,最小值。
這是一份格式較為規則的文字檔案報表。 #檔案頭有一些無用的描述資訊 ~ 深度 電阻值 放射性值 10 1.5 2.4 20 0.4 1.9 30 2.5 0.5 40 1.3 50 3.1
先不解釋,直接貼指令碼:
#載入檔案,並過濾空行
$fullText=Get-Content .\a.txt | where { !([string]::IsNullOrWhiteSpace($_))}
#尋找檔案頭開始標誌
$startFlagIndex=-1
For ($i = 0; $i -lt $fullText.Length; $i++)
   {
      if($fullText[$i].Contains("~"))
      {
        $startFlagIndex=$i
        break
      }
 
   }
#去掉檔案頭
$fullText=$fullText | Select-Object -Skip ($startFlagIndex+1)
 
<#
 #將檔案轉換成CSV格式,然後再從CSV轉換成物件
 #幾經周折後,再要深入進行資料處理,將會變得非常方便
#>
$objs=$fullText | foreach{
    $tokens= $_.Split(' ',[StringSplitOptions]::RemoveEmptyEntries)
    '"{0}"' -f [string]::Join('","',$tokens)
} | ConvertFrom-Csv
 
#統計放射性值不為空的物件
Write-Host "統計放射性值為空的物件"
$objs | where { $_.放射性值 -ne $null } | Format-Table -AutoSize
 
#求所有電阻值的個數,平均值,總和,最大值,最小值
Write-Host "求所有電阻值的個數,平均值,總和,最大值,最小值:"
$objs |  Measure-Object -Property 電阻值 -Average -Sum -Maximum -Minimum
輸出示例: 回過頭再看,指令碼完全可以優化為一個foreach迴圈,每行文字只遍歷一次。之所以多次一舉,是為了演示分析問題的過程。 同樣也能得出一個結論,如果可以盡最大可能從資料來源拿到CSV檔案格式的資料,PowerShell處理起來更方便,一行搞定! (二) 問題描述: 給出一段學生成績文字檔案如下:
李一 93 王二 83 王三 93 李四 60 王五 75 馬六 61 孫七 75 劉八 75
要求打印出成績相同的學生及成績。
李一 93 王三 93 王五 75 孫七 75 劉八 75
問題分析: 第一遍遍歷,先須要一張雜湊表儲存各個成績的出現的次數。 第二遍遍歷,將成績出現次數大於2的名單列印。
$scoreTables=@{}
$stus=Get-Content .\ScoresFile.txt |
foreach {
$stu=$_ -split " "
if($scoreTables.ContainsKey($stu[1]))
{
 $scoreTables[$stu[1]]++
}
else {
    $scoreTables[$stu[1]]=1
}
@{ Score=$stu[1];Name=$stu[0] }
}
 
$stus | where {
$scoreTables[$_.Score] -gt 1
} | foreach {"{0} {1}" -f $_.Name,$_.Score }
用group-object實現統計,比較完美,稍作整理,也貼在這裡:
Get-Content .\ScoresFile.txt | ForEach-Object {
[PSCustomObject]@{
 Name = $_.split()[0]
 Value = $_.split()[1]
 }
} | Group-Object Value | Where-Object { $_.Count -gt 1 }|
 ForEach-Object { $_.Group | ForEach-Object { "{0} {1}" -f $_.name,$_.value } }
 #為了和原始檔格式保持一直,加入格式化
(三) 原始文字:”data1″:111,”data2″:22,”data3″:3,”data4″:4444444,”data5″:589 要求:轉換成物件

PowerShell命令與指令碼(8)——迴圈

輸出: (四)提取CSV檔案中的域名
擴充套件:CSV 逗號分隔值(Comma-Separated Values,CSV,有時也稱為字元分隔值,因為分隔字元也可以不是逗號),其檔案以純文字形式儲存表格資料(數字和文字)。純文字意味著該檔案是一個字元序列,不含必須像二進位制數字那樣被解讀的資料。CSV檔案由任意數目的記錄組成,記錄間以某種換行符分隔;每條記錄由欄位組成,欄位間的分隔符是其它字元或字串,最常見的是逗號或製表符。通常,所有記錄都有完全相同的欄位序列。 “CSV”並不是一種單一的、定義明確的格式(儘管RFC 4180有一個被通常使用的定義)。因此在實踐中,術語“CSV”泛指具有以下特徵的任何檔案:
  1. 純文字,使用某個字符集,比如ASCII、Unicode、EBCDIC或GB2312(簡體中文環境)等;
  2. 由記錄組成(典型的是每行一條記錄);
  3. 每條記錄被分隔符分隔為欄位(典型分隔符有逗號、分號或製表符;有時分隔符可以包括可選的空格);
  4. 每條記錄都有同樣的欄位序列。
在這些常規的約束條件下,存在著許多CSV變體,故CSV檔案並不完全互通。然而,這些變異非常小,並且有許多應用程式允許使用者預覽檔案(這是可行的,因為它是純文字),然後指定分隔符、轉義規則等。如果一個特定CSV檔案的變異過大,超出了特定接收程式的支援範圍,那麼可行的做法往往是人工檢查並編輯檔案,或通過簡單的程式來修復問題。因此在實踐中,CSV檔案還是非常方便的。
有一個CSV檔案,其中包含了成千上萬的URL連結,每個連結都可能是完整路徑包含了資料夾,變數等。希望提取出其中的域名以便於進行深度分析。 我的CSV檔案只有一列:
"https://www.pstips.net/diff-with-currentculture-and-currentuiculture.html" "https://www.pstips.net/tag/powershell-v3" "https://www.pstips.net/powershell-download-files.html" "http://www.notelee.com/cs0012-the-type-system-object-is-defined-in-an-assembly-that-is-not-referenced.html" "http://www.notelee.com/scom-create-wmi-perf-rule.html" "http://www.lonsoon.com/2013/04/94.html" "http://www.lonsoon.com/2013/05/101.html"
期望的輸出URL中所有的域名結果 分析:可以利用Import-csv命令,因為csv檔案沒有標題,需要臨時指定標題。然後利用.NET中的類System.Uri Import-Csv .\file.csv -Header "link" | foreach { ( [uri]($_.link) ).Host } 再通過Group-Object進行分組去重