我正在嘗試在 Powershell 中撰寫腳本來轉換德語變音符號
?, ?, ü, ? to ae, oe, ue, ss
?, ?, ü, ? to AE or Ae, UE or Ue, and SS.
問題是我還需要根據變音符號的位置進行區分。
üNLü > UENLUE
ünlü > Uenlue (Ue)
SCHNEEWEI? > SCHNEEWEISS
Schneewei? > Schneeweiss
Ge?l > Gessl
GE?L > GESSL
Josef ?binger > Josef Oebinger (one string)
Jürgen MüLLER > Juergen MUELLER (one string)
破壞我一天的主要問題是變音符號?
? 沒有大小寫
我需要根據前一個字符是大寫還是小寫來識別 ?
我嘗試過各種正則運算式,例如[??ü?A-Z]{1,}(?![\sa-z?ü?])[??ü?A-Z]或[??ü?][^a-z]
我基本上不可能搞清楚是ss還是SS。除此之外,像 üNLü 這樣的詞只能用一個元音變音來識別,因為帶元音變音的字母位于單詞的末尾。
我需要 3 個匹配的正則運算式模式。一種用于大寫,一種用于小寫,一種用于混合大小寫 (Oebinger)
然后將這 3 個模式放入 powershell 中的 3 個 IF 條件中,然后我可以根據匹配的模式進行盲目轉換。
[??ü?][^a-z]適用于 üNLü > UENLUE
[??ü?][^A-Z]為尤爾根作業 > 于爾根
但是 Schneewei? 和 SCHNEEWEI? 中的 ? 與這兩種模式都匹配。那不是我想要的。
我需要一個可以檢查 ? 之前和之后的字母是小寫還是大寫的模式。如果小寫大于 ? = ss,如果大寫則 ? = SS
第三種情況,混合情況并不需要單獨的正則運算式。我基本上可以使用 String Jürgen MüLLER,通過兩種模式在 powerscript 中運行它。First Pattern 會將其轉換為 Jürgen MUELLER。拿走這個并再次運行它以獲取 Juergen MUELLER。
變音符號 ? 始終相同。小寫 = 大寫。這就是讓整個事情變得如此困難的原因。
我正在失去希望。請幫幫我。
uj5u.com熱心網友回復:
PowerShell (Core) 7 提供了一個簡潔的解決方案,因為那里的-replace操作員接受一個腳本塊作為替換運算元,它可以根據找到的每個匹配項進行靈活、動態的替換:
$strings = @(
'üNLü' # > UENLUE
'ünlü' # > Uenlue (Ue)
'SCHNEEWEI?' # > SCHNEEWEISS
'Schneewei?' # > Schneeweiss
'Ge?l' # > Gessl
'GE?L' # > GESSL
'Josef ?binger' # > Josef Oebinger
'Jürgen MüLLER' # > Juergen MUELLER
'THE? H?RSHERIN' # > THEOE HAERSHERIN
'M??IG' # > MAESSIG
)
$strings `
-replace '[??ü](?:(?=?)|\p{L})?', {
([string] $_.Value[0]).Normalize('FormD')[0]
([char]::IsUpper($_.Value[1] ?? $_.Value[0]) ? 'E' : 'e')
$_.Value[1]
} `
-replace '.?', {
$_.Value[0] ([char]::IsUpper($_.Value[0]) ? 'SS' : 'ss')
}
筆記:
- 呼叫
.Normalize('FormD')[0]包含單個變音符號的字串實際上將該字符轉換為其 ASCII 基本字母;例如,ü變成u-seeSystem.String.Normalize。
在Windows PowerShell (最新和最后一個版本為 v5.1的舊版、僅限 Windows 的版本)中:
- 您需要直接呼叫底層的.NET API,即
[regex]::Replace() - 您還需要使用
if陳述句來代替三元運算子 (<condition> ? <if-true> : <else>)和空合并運算子 (??),它們也僅在 PowerShell (Core) 7 中可用。
因此,解決方案要復雜得多:
$strings | ForEach-Object {
$aux =
[regex]::Replace(
$_,
'[??ü](?:(?=?)|\p{L})?',
{
param($m)
([string] $m.Value[0]).Normalize('FormD')[0]
$(if ([char]::IsUpper($(if ($m.Value[1]) { $m.Value[1] } else { $m.Value[0] }))) { 'E' } else { 'e' })
$m.Value[1]
},
'IgnoreCase'
)
[regex]::Replace(
$aux,
'.?',
{
param($m)
$m.Value[0] $(if ([char]::IsUpper($m.Value[0])) { 'SS' } else { 'ss' })
},
'IgnoreCase'
)
}
注意:以上是 PowerShell (Core) 7 解決方案的直接等效項,但第二個[regex]::Replace()呼叫可以替換為以下內容,如js2010 的回答中所示:
$aux -creplace '(?<=\p{Ll})?', 'ss' -creplace '(?<=\p{Lu})?', 'SS'
uj5u.com熱心網友回復:
謝謝你提出這么有趣的問題!
我認為有兩種方法可以解決這個問題。
您當前采用的方法似乎是嘗試在替換字串中執行此操作。這可能有效,但我懷疑您想要使用-creplace或明確區分大小寫的正則運算式。
我會嘗試的方法是使用正則運算式替換評估器。這些在 PowerShell 中很容易做到,因為您可以將 a[ScriptBlock]轉換為任何委托。
我相信這個腳本可以解決問題:
$inputString = @'
üNLü
ünlü
SCHNEEWEI?
Schneewei?
Ge?l
GE?L
Josef ?binger
Jürgen MüLLER
'@
$UmulatesPattern = [Regex]::New('[??ü??ü?]')
$UmulatesPattern.Replace($InputString,{
param($match)
$wasCapitalized = $match.Value -cmatch '\p{Lu}'
$lastCharacter =
if ($match.Index -gt 1) {
$inputString[$match.Index - 1]
} else { ' ' }
$nextCharacter =
if ($match.Index -lt ($inputString.Length - 2)) {
$inputString[$match.Index 1]
} else { ' ' }
$shouldCapitalizeAll =
$lastCharacter -cmatch '[\s\p{Lu}]' -and
$NextCharacter -cmatch '[\s\p{Lu}]'
$replacement =
switch ($match) {
"?" {"ae"}
"?" {"oe"}
"ü" {"ue"}
"?" {"ss"}
}
if ($shouldCapitalizeAll) {
$replacement.ToUpper()
} elseif ($wasCapitalized) {
'' $replacement.Substring(0,1).ToUpper() $replacement.Substring(1)
} else {
$replacement
}
})
正如上面的答案所表明的那樣,評估者之所以有用是因為評估者可以輕松地根據匹配的周圍環境進行替換。
運行上面的代碼會生成這個串列,這似乎符合您想要的體驗:
UENLUE
Uenlue
SCHNEEWEISS
Schneeweiss
Gessl
GESSL
Josef Oebinger
Juergen MUELLER
唯一的其他注意事項是,在確定字母對是否應大寫時,我最終使用了前后字符的背景關系。
uj5u.com熱心網友回復:
將一些注釋放在一起,使用查找大寫和小寫字符,區分大小寫替換:
'SCHNEEWEI?' -creplace '(?<=\p{Lu})?','SS'
SCHNEEWEISS
'Schneewei?' -creplace '(?<=\p{Ll})?','ss'
Schneeweiss
'?' -cmatch '\p{Ll}' # lower case
True
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/518215.html
