05 Windows批處理中的字串和布林資料型別

公子奇的博客發表於2024-09-05

要了解在批處理中分配資料型別的第一件事是批處理不允許分配資料型別。所有批處理變數都是等效的。從本質上講,儲存數字、文字甚至布林值的變數之間沒有區別。但是,設定為數字的變數可以被視為數字,我們將在後面的文章中重點討論這些資料型別。

在本文中,在描述了所有批處理資料型別之後,我們將學習字串和字元變數。還將使用子字串和文字替換的方法進一步探索字串。布林值不是由批處理的建立者設計的,但是我們將向您展示如何構建和使用這種有用的資料型別。

常見的資料型別

許多程式語言不僅允許而且要求在為每個變數賦值或以任何方式使用它之前將其宣告為特定的資料型別。不同的語言有不同的資料型別,這裡列出來一些常用的資料型別列表:

  • 字元 --- 單個字母數字字元

  • 字串 --- 0到多個字母數字字元

  • 整數 --- 正負整數

  • 浮點數 --- 帶小數點的數字

  • 布林型 --- true或false

不管申明資料型別是好還是壞,批處理變數都沒有宣告具體的資料型別。當直譯器第一次發現一個新的變數名時,它就會無中生有。這種做法確實有很大的靈活性,但它可能是棘手和危險的。一個被使用了十幾次的變數的一個拼寫錯誤的例項被直譯器認為是一個完全不同的變數,編譯器不會捕捉到這個錯誤。相反,它被視為一個可能什麼都解決不了的新變數。

變數可以被賦值為整數,並且可以對其執行算術運算。然後可以為同一變數分配文字並將其視為字串。這也意味著可能會無意中對包含字串的變數執行算術,但好處是,在將數字寫入控制檯或報告時,可以很容易地將其視為字串,而無需進行任何型別的轉換。

儘管您不能分配資料型別,但是您可以建立變數並將它們視為型別之一,但是—我必須強調這一點是每個批處理變數的底層結構實際上只是一些無法描述的記憶體位元組。

字元

一個字元僅僅是一個位元組的文字;在批處理的世界中,可以把它看作一個非常短的字串,因為它被當作任何只有一個字元的字串一樣對待。

字串

字串是任意長度的文字,包含字母字元、數字和/或特殊字元。下面的命令將aString變數設定為一個5個單詞的字串:

set aString=Awesome Batch Code Dares Excellence

包括嵌入的空格在內,它的長度總計為35個字元,或者用程式設計師的話說,就是位元組。

許多特殊字元,如美元符號和英磅符號,可以顯式地包含在字串中,但其他字元,如百分號,不能包含在字串中,因為它們在批處理中有特定的用途。在後面的文章中,我們將討論跳脫字元,即如何允許在字串中包含所有字元,但是現在,要理解直譯器在遇到字串中的感嘆號時不會中止,但是您可能看不到預期的結果。例如,賦給這個變數的值的最後一個字元是感嘆號:

rem 開啟延遲擴充套件
setlocal EnableDelayedExpansion

set aString=Awesome Batch Code Dares Excellence!
> con echo A String is "%aString%"

下面是echo命令的結果:

A String is "Awesome Batch Code Dares Excellence"

標點符號沒有寫入控制檯,因為它沒有包含在字串變數中。

注意:

正如在前面文章中提到的,我們假設延遲擴充套件始終是啟用的。這個示例就是一個很好的例子,因為如果禁用了延遲展開,那麼感嘆號就只是另一個字元,而不是用於解析變數的分隔符。該字元將作為值的一部分包含,並將與其餘文字一起寫入控制檯。能夠將感嘆號視為簡單的文字可能是禁用延遲擴充套件的唯一好處。與延遲擴充套件提供的功能相比,這個微不足道的優勢顯得微不足道,這就是我推薦普遍使用延遲擴充套件的原因。

在後面的文章中,我們將討論如何將字串和其他資料型別寫入檔案,但在這裡,我將解釋如何構建、連線、子字串和操作字串。

構建和連線

前面的示例使用單個set命令將值Awesome Batch Code dare Excellence分配給一個變數。下面的六行執行相同的任務:

set a=Awesome
set b=Batch &
set c=Code
set d=Dares
set e= Excellence
set aString=%a% %b%%c% %d%%e%

在實踐中,這種方法對於構建字串來說非常低效,但是它很好地演示了連線的原理。

由字母表的前五個字母定義的變數分別被設定為一個單詞。然後在最後一行,所有五個變數被解析並連線在一起以建立aString。注意結果中的四個嵌入空格。一個來自批處理之後的尾隨空格,另一個來自Excellence之前的前導空格,另外兩個嵌入在最後一個set命令中。

前面的例子展示瞭如何透過連線其他字串來建立字串,但你也可以在現有字串上新增其他文字:

set longText=This field contains a brutal run-on sentence and if its prose
set longText=%longText% were to be typed into a single line the reader would
set longText=%longText% be forced to scroll way over to the right to read what
set longText=%longText% you are reading now and then scroll way back to the
set longText=%longText% left after mercifully getting to this period.

在這裡,一個字串被附加了四次額外的文字,以建立一個非常長的字串。這種方法是我建立長字串變數的首選方法,但是您也可以使用“延續字元”或插入符號(^)來完成相同的任務。當直譯器看到行尾的插入符號時,它會將下一行附加到該行:

set longText=This field contains a brutal run-on sentence and if its prose ^
were to be typed into a single line the reader would be forced to scroll way^
 over to the right to read what you are reading now and then scroll way back ^
to the left after mercifully getting to this period.

在這個例子中,三個插入符號被用來組成一個四行set命令。第一行和第三行在插入符號前面有一個空格,它們的下一行從第一個位元組開始,導致單詞之間有一個空格。為了演示做同樣事情的另一種方法,第二個插入符號緊跟著單詞way,下一行在下一個單詞之前有一個空格,over。結果是一長串單詞,全部由一個空格分隔。

我並不推薦這種使用方式,原因很簡單,它會破壞我們的縮排編碼風格。我將大多數命令縮排兩個或多個空格,如set命令的第一行所示,但是後面一行開頭的任何空格都被認為是附加文字的一部分。這實際上意味著這些行必須左對齊。

重要:

我把“延續字元”放在引號裡,因為這是一個粗略的簡化。插入符號實際上是一個跳脫字元。

子串

任何稱職的語言都會支援檢索字串一部分的子字串函式,批處理也可以勝任這項任務。對於接下來的幾個例子,讓我們考慮像之前一樣設定aString變數:

set aString=Awesome Batch Code Dares Excellence

子字串函式需要兩個數字,偏移量或起始位置以及所需文字的長度。令人驚訝的是,批處理使用了在現代語言中占主導地位的零偏移(下標從0開始數),而不是20世紀語言中更常見的一偏移。這意味著第一個位元組是位置0(不是1),第二個位元組是位置1,第100個位元組是位置99,以此類推。

子串的語法有點笨拙。這個變數通常用百分號解析,但是在結束的百分號前面有一個冒號、一個波浪號、偏移量、一個逗號,最後是長度。因此,以下語法返回aString變數的前三個字元:

set substring=echo %aString:~0,3%

0的偏移量告訴直譯器從第一個位元組開始,長度定義為3,導致文字Awe被分配給subString。

下面的程式碼從字串的第一個單詞some中提取文字:

set subString=%aString:~3,4%

我們需要從第四個位元組開始,這是一個零偏移量3。如果您發現零偏移量令人困惑,請將偏移量視為子字串之前的位元組數。更明顯的是,長度是4。

下面是用硬編碼的to和兩個空格組合在一起的兩個子字串:

set phrase=%aString:~15,3% to %aString:~8,5%

第15個位元組是Code中的大寫C,因此第一個子字串是單詞的剩餘三個位元組。第八個位元組是Batch前面的空格,所以接下來的五個位元組包含了整個單詞。結果是對原始字串的重新解釋:ode to Batch。

如果沒有定義長度,直譯器返回字串的剩餘部分。為了演示,下面的子字串沒有長度,前面沒有逗號。偏移量對應於35個位元組變數中之前的25位元組:

set subString=%aString:~25%

結果是subString被分配了字串Excellence,即原始字串的最後10個位元組。

偏移量為負數

請注意以下示例中的負偏移量。有趣的是,這也將 Excellence 分配給變數:

set subString=%aString:~-10%

負偏移量表示起始位置相對於字串的末尾,而不是開始,這意味著-10告訴直譯器子字串從字串末尾開始10個位元組。因為沒有給出長度,所以它返回文字的剩餘部分。只要變數存在值,%aString:~-1%是檢查其最後一個位元組的簡單方法。

這兩個命令產生相同的ode子字串:

set subString=%aString:~15,3%
set subString=%aString:~-20,3%

第一個命令的偏移量是從原始字串開始的15個位元組,而第二個命令透過從35位元組變數的末尾開始計算20個位元組來找到相同的位置。

長度為負數

負長度的工作原理與此類似。不要把它想象成長度;可以把它看作字串末尾而不是子字串中的位元組數。例如,下面的程式碼返回一個去掉第一個和最後一個位元組的字串:

set subString=%aString:~1,-1%

你甚至可以使用負長度的負偏移量。下面提取字串的倒數第二個位元組:

set subString=%aString:~-2,-1%

-2的偏移量告訴直譯器從倒數第二個位元組開始,-1的長度表示刪除最後一個位元組。

子字串實踐

在批處理中檢索子字串的一個很好的特性是,如果呼叫超出字串長度的子字串,則返回null。因此,直譯器在遇到%aString:~99,1%的35位元組字串時不會崩潰,也不會返回一個空格。相反,它只返回一個空字串。這是一種方便的確定字串長度的方法,不用擔心編譯程式碼中普遍存在的空指標異常。如果第36個位元組等於null(即"%aString:~35,1%" equ ""),但第35個位元組有值,則字串的長度正好是35位元組。

但是,此語法僅在對已填充的字串進行子字串處理時有效。正如我剛才提到的,如果字串的長度在1到35個位元組之間,%aString:~35,1%解析為空,當然,如果字串的長度在36個位元組或更長,它將解析到第36個位元組。但是,如果字串為空或設定為null,則%aString:~35,1%解析為~35,1或冒號和末尾分隔符之間的所有內容。同樣,由於這個問題,當嘗試檢查空字串的最後一個位元組時,%aString:~-1%解析為~-1,而不是您可能期望的null。

現在您知道了如何從另一個字串中提取字串的任何部分,但是在前面的示例中,所有的偏移量和長度都是硬編碼的。通常,這兩個數字將是變數。在下面的例子中,偏移量和長度被定義為命名的變數,並在第三個命令中使用:

rem 不要忘記開啟延遲擴充套件

set offset=15
set length=3
set subString=!aString:~%offset%,%length%!

包含偏移量和長度的百分號首先將這些變數解析為它們的數值。然後加上感嘆號,這樣!aString:~15,3!解析為我們熟悉的ode,這是實現延遲擴充套件的另一個成功。

在後面的文章中,我將討論算術運算,在完成之後,您將能夠計算儲存整數值的變數,這些整數值將用作偏移量和長度來查詢子字串。

文字替換

批處理還有一個方便的機制,可以用其他文字替換字串的全部或部分。例如,假設以下變數包含這個不推薦的檔名:

set filNm=File_Name_With_Underscores.docx

如果不喜歡這個檔名,可以將下劃線更改為破折號。在後續文章中,我們也將介紹重新命名檔案的推薦命令,但這裡我將討論如何構建一個包含新檔名的變數。

文字替換語法類似於用於子字串的語法。變數和冒號像以前一樣被百分號包圍,但是現在沒有波浪號了。相反,冒號之後是要搜尋和更改的文字,後面跟著等號分隔符,最後是替換文字:

set newFilNm=%filNm:_=-%

每個下劃線字元(_),而不僅僅是遇到的第一個下劃線字元,都被更改為破折號(-),從而產生File-Name-With-Underscores.docx。注意不要更改過多的文字。

看看這個檔名,將“下劃線”改為“破折號”也是有意義的。幸運的是,批處理不要求目標文字和替換文字的長度相同,所以這個額外的命令進一步將這個變數的值更新為File-Name-With-Dashes.docx:

set newFileNm=%newFileNm:underscor=Dash%

由於兩個單詞都以es結尾,所以我使用單數 Dash 作為替換文字,目標文字是 underscor,這不是一個完整的單詞。另外,請注意,在變數的值中,Underscores 是大寫的,而在替換語法中,underscor 是小寫的。非常重要的是,批處理會進行不區分大小寫的替換。目標文字可以是任何一種情況,甚至可以是混合情況,對結果沒有影響,但是替換文字將完全按照命令中輸入的方式使用。因此,%newFilNm:UNDERscor=Dash%在功能上與上一個命令中的變數解析相同,但是%newFilNm:UNDERscor=DASH%將產生一個新的檔名File-Name-With-DASHes.docx

這很奇妙,但前面兩個命令顯示了兩種不同的賦值方法。第一個將修改後的filNm值賦給newFilNm,使filNm保持不變。第二個命令將newFilNm重新分配給它自己,以便它的最終值反映兩個文字替換。這兩種方法為您提供了靈活性,可以就地更改變數的值,也可以維護兩個變數,一個包含舊文字,一個包含新文字。

還可以使用延遲擴充套件將目標文字(target)和替換文字(repl)轉換為變數。這裡有一個例子:

set targ=Love
set repl=Hate
set aString=I Love Broccoli
set aString=!aString:%targ%=%repl%!

結果是字串“I Hate Broccoli”。

文字搜尋是文字替換語法的一個很好的應用。在後續文章中,我們將比較和對比確定一個字串是否是另一個字串的一部分的兩種方法。findstr命令工作得很好,但是基於前面語法的方法執行時間很短。劇透警告:文字搜尋邏輯將搜尋到的文字替換為null,並將結果與原始文字進行比較。如果它們不同,則找到了文字。

布林值

布林值一直存在於編譯語言中,有兩種,而且只有兩種可能的狀態:真(true)或假(false)。一旦設定好,您就可以單獨使用它們作為if命令中的條件子句,將其計算為true或false,從而確定是否應該執行程式碼塊。批處理並不顯式地支援布林值,但是隻要稍微使用一點技巧,您就可以建立它們。

“God.txt存在嗎?”在前面的文章中,我展示瞭如何使用if命令來確定文字檔案是否存在:

if exist D:\Batch\God.txt (
   set god=Found
) else (
   set god=NotFound
)

根據檔案在某一時刻的狀態將變數設定為FoundNotFound。然後可以在將來詢問god變數,以確定god .txt在較早的時間是否存在。它可以執行,但有點笨重;布林值將提供更優雅的解決方案。然後,您可以輕鬆地在整個程式碼中多次引用布林值,甚至可能重置它。

設定和計算布林值

在批處理中,像所有變數一樣,布林值實際上只是一些文字,但是這些文字可以被看作為true或false。按照慣例,我總是在布林變數名的前面加上小寫b和大寫字元,以使其作為布林值突出。(一個更詳細和描述性的選項是以bool文字開頭。)讓我們複製上一個示例中的邏輯,唯一的區別是變數god被布林值bGod替換,如果找到God .txt,則將其設定為true,如果未找到則設定為false:

if exist D:\Batch\God.txt (
   set bGox=true==true
) else (
   set bGox=false==x
)

在其他語言中,布林值被顯式設定為true或false。例如,一個有效的Java命令是bGod = true;但是前面的關於批處理中的布林值的set命令看起來有點不同;特別地,每個都有三個等號。第一個僅僅是用來賦值,另外兩個是用來指定值。當 if 命令的條件子句為true時,我們將bGod設定為truetrue;如果不是,則falsex為值。這當然看起來很奇怪,但是現在這個變數,雖然從技術上講仍然只是文字,但可以作為另一個if命令的條件子句進行判斷,如下所示:

if %bGod%  > con echo Let us pray.

如果bGod被設定為我們認為的true,直譯器將If %bGod%解析為If true == true。變數包含一個相等運算子,雙等號,兩邊的值相同。(不要問運算子周圍的空格,但這是直譯器看到的。)將所有這些放在 if 命令之後,它的計算結果為true。

但是,如果將變數設定為我們認為的false,則該命令將被解析為If false == x,這將比較兩個明顯不同的值,從而導致If命令後面的程式碼不執行。

帶布林值的if命令也可以與not子句一起使用:

if not %bGod%  > con echo Live every day to the fullest.

如果文字(if not %bGod%)解析為If not true == true,則計算結果 not true 或 false。但是當文字解析為雙否定if not false == x時,它的計算結果為not false或not true,並將文字寫入控制檯。

布林值轉換為字串

我選擇truetrue作為true的值,但是xx或0 == 0也可以,並且需要更少的按鍵。即使falsefalse也會求值為真,但這並不難。同樣,falsex可以包含任意兩個不同的字串,但我選擇了這兩個值,以便文字true或false在布林值的前面。布林變數的結構允許您在編譯程式碼中模擬布林值的另一個特性——將布林值轉換為字串。

作為結構化的,您可以將批處理中的布林值轉換為字串true或false,只需去掉兩個等號之後和包含的所有內容。當我們在看到for命令時,我將展示它是如何工作的,但是現在,下面這行程式碼將截斷多餘的文字:

for /F "delims==" %%b in ("%bGod%") do  set bStrGod=%%b

在對一個有效的布林值執行此命令後,名為bStrGod的布林字串變數將包含true或false。

如果布林變數的字首是b,那麼用b作為布林字串變數的字首可能是有意義的。

總結

字串在批處理中無處不在,在本文中,我們詳細介紹瞭如何構建和連線它們。子字串和文字替換是所有批處理程式設計師都應該掌握的兩個強大而有用的工具,儘管它們的語法很深奧。布林值並不是那麼普遍,但我希望我展示了這種未充分利用的資料型別的有用性。

在下一篇文章中,我們將繼續討論資料型別,深入研究數值資料型別。我將詳細介紹三種不同進位制的整數和浮點數,為探索批處理中如何處理算術提供了一個很好的機會。

本文由部落格一文多發平臺 OpenWrite 釋出!

相關文章