簡體   English   中英

將 C# 代碼轉換為 powershell:scriptblock-delegate

[英]convert C# code to powershell: scriptblock-delegate

這是我想轉換為“powershell方式”的代碼:

private static Regex unit = new Regex(
        @"(?<sequence>\d+)\r\n(?<start>\d{2}\:\d{2}\:\d{2},\d{3}) --\> (?<end>\d{2}\:\d{2}\:\d{2},\d{3})\r\n(?<text>[\s\S]*?\r\n\r\n)", 
        RegexOptions.Compiled | RegexOptions.ECMAScript);


    output.Write(
        unit.Replace(input.ReadToEnd(), delegate(Match m)
        {
            return m.Value.Replace(
                String.Format("{0}\r\n{1} --> {2}\r\n",
                    m.Groups["sequence"].Value,
                    m.Groups["start"   ].Value,
                    m.Groups["end"     ].Value),
                String.Format(
                    "{0}\r\n{1:HH\\:mm\\:ss\\,fff} --> " + 
                    "{2:HH\\:mm\\:ss\\,fff}\r\n",informatifetcourrier.com   CuImE
                    sequence++,
                    DateTime.Parse(m.Groups["start"].Value.Replace(",","."))
                            .AddSeconds(offset),
                    DateTime.Parse(m.Groups["end"  ].Value.Replace(",","."))
                            .AddSeconds(offset)));

而我的嘗試:

$text=@'
2
00:00:03,601 --> 00:00:06,603
<i>Vous devrez trouver quelqu'un
qui pense différemment pour l'attraper.</i>
'@

$regex ='(?m)(?<sequence>\d+)\r\n(?<start>\d{2}\:\d{2}\:\d{2},\d{3}) --\> (?<end>\d{2}\:\d{2}\:\d{2},\d{3})\r\n(?<text>[\s\S]*?\r\n\r\n)'

$r = New-Object System.Text.RegularExpressions.Regex $regex

$MatchEvaluator = 
{  
    param($m) 

    $m.value.replace([string]::Format("{0}\r\n{1} --> {2}\r\n",
        $m.Groups["sequence"].Value,
        $m.Groups["start"   ].Value,
        $m.Groups["end"     ].Value),
    [string]::Format("{0}\r\n{1:HH\\:mm\\:ss\\,fff} --> {2:HH\\:mm\\:ss\\,fff}\r\n",
        [datetime]::Parse($m.Groups["start"].Value.Replace(",",".")).AddSeconds(1),
        [datetime]::Parse($m.Groups["end"  ].Value.Replace(",",".")).AddSeconds(1)))
}
$result = $r.Replace($text, $MatchEvaluator)

但它不起作用。 感謝您的幫助。

我知道我必須使用 scriptblock-delegate 才能達到我的目的。

你在這里遇到了幾個問題。 這是一個有效的版本:

$text=@'
2
00:00:03,601 --> 00:00:06,603
<i>Vous devrez trouver quelqu'un
qui pense différemment pour l'attraper.</i>
'@

$regex = [regex]'(?m)(?<sequence>\d+)\s*$\s*(?<start>\d{2}:\d{2}:\d{2},\d{3}) --> (?<end>\d{2}:\d{2}:\d{2},\d{3})\s*$\s*(?<text>.*$\s*.*$)'

$MatchEvaluator = {  
    param($m) 

    $oldValue = "{0}`r`n{1} --> {2}`r`n" -f $m.Groups["sequence"].Value,
                    $m.Groups["start"].Value, $m.Groups["end"].Value
    $seq   = 5 + $m.Groups["sequence"].Value
    $start = ([DateTime]$m.Groups["start"].Value.Replace(",",".")).AddSeconds(1)
    $end   = ([DateTime]$m.Groups["end"].Value.Replace(",",".")).AddSeconds(1)
    $newValue = "{0}`r`n{1:HH:mm:ss,fff} --> {2:HH:mm:ss,fff}`r`n" -f $seq,$start,$end
    $m.value.replace($oldValue, $newValue)
}

$result = $regex.Replace($text, $MatchEvaluator)
$result

首先,在 PowerShell 雙引號字符串中,您將`r`n用於 CRLF。 其次,您缺少上面替換字符串$seq的參數。 第三,您不需要在正則表達式中轉義: 第四, -f運算符是一個包裝器,比[String]::Format()更方便使用。

這輸出:

7
00:00:04,601 --> 00:00:07,603
<i>Vous devrez trouver quelqu'un
qui pense différemment pour l'attraper.</i>

我不知道您想如何修改序列號,所以我只添加了 5。

非常感謝基思·希爾。 這是我的工作代碼:

$file = "D:\subtitles\Hannibal - 02x10 - eng.srt"
$text =get-content($file) -Raw     # powershell V3

Write-Output "offset, in seconds (+1,1, -2,75):"

[Double]$offset = 0

while(![Double]::TryParse((Read-host),[ref] $offset))

{

Write-Output "Not a Number. Do again"

 }

$regex = [regex]'(?m)(?<sequence>\d+)\s*$\s*(?<start>\d{2}:\d{2}:\d{2},\d{3}) --> (?<end>\d{2}:\d{2}:\d{2},\d{3})\s*$\s*(?<text>.*$\s*.*$)'

$MatchEvaluator = {  
param($m) 

$oldValue = "{0}`r`n{1} --> {2}`r`n" -f $m.Groups["sequence"].Value,
                $m.Groups["start"].Value, $m.Groups["end"].Value
$seq   =+$m.Groups["sequence"].Value
$start = ([DateTime]$m.Groups["start"].Value.Replace(",",".")).AddSeconds($offset)
$end   = ([DateTime]$m.Groups["end"].Value.Replace(",",".")).AddSeconds($offset)
$newValue = "{0}`r`n{1:HH:mm:ss,fff} --> {2:HH:mm:ss,fff}`r`n" -f $seq, $start,$end
$m.value.replace($oldValue, $newValue)
}

$result = $regex.Replace($text, $MatchEvaluator) | out-file -Encoding utf8 "D:\subtitles\Hannibal - 02x10 - eng_offset_$offset.srt"

我的下一步是合並英語和法語字幕(例如:70% 的法語和 30% 的英語)。 任何建議將受到歡迎。

一些用於教學目的的細節:

mjolinor 的評論是正確的,因為正則表達式確實不正確,因為 powershell 用單個 \\n 表示此處字符串中的行尾。

此外,如上所述,字符串末尾沒有 \\n,因為此處字符串的末尾由 \\n'@ 標記(即行首的 '@),因此最后一個 \\n 是一部分結束標記,而不是字符串。

不幸的是,僅僅刪除無關的 \\r 和 \\n 字符轉義是行不通的。 沒有具體的匹配來定義 <text> 在哪里結束, [\\s\\S]*? 將匹配為空(讓整個模式成功的最小匹配)。 要匹配所有 <text>,請使用 [\\s\\S]*(貪婪版本)或使用 [\\s\\S]*?$ 強制匹配到字符串的末尾。

此外,: 和 > 不是元字符(如 . 或 *),因此不需要轉義(盡管它不會造成傷害)。 基思希爾修復了這個問題,但沒有提到它。 此外,指定 MultiLine 選項標志 (?m) 沒有任何意義,因為原始模式沒有受影響的錨點(^ 和 $)並且 C# 版本無論如何都沒有設置它。 即使 <text> 捕獲組使用 [\\s\\S]*?$,這個 $ 也匹配字符串的結尾,而不是中間的 \\n(盡管如果存在,它會留下不匹配的終止 \\n)。 因此(修復而不是替換)正則表達式應該是:

 (?<sequence>\d+)\n(?<start>\d{2}:\d{2}:\d{2},\d{3}) --> (?<end>\d{2}:\d{2}:\d{2},\d{3})\n(?<text>[\s\S]*)

注意:此解釋來自原始問題。 隨后發布的“工作代碼”顯示 $text 值是從文件中獲取(原始)的,因此可能確實包含 \\r\\n 作為行尾標記。

雖然我會說 Keith Hill 使用 \\s*$\\s* 來匹配行尾的答案更可靠,因為它同時匹配 \\n 和 \\r\\n(以及任何后面的或尚未匹配的前面的空格),如果文件的結構是已知和固定的,然后使用無界量詞來匹配固定部分可能會導致細微的錯誤。 在這種情況下,使用 \\s*$\\s* 匹配 <end> 和 <text> 捕獲組之間的 \\r\\n 將導致 <text> 開頭的任何空格被丟棄。 如果行尾標記只能是 \\n 或 \\r\\n 那么 \\r?\\n 更安全。

此外,使用 .*$\\s*.*$ 意味着 <text> 匹配一個(可能為空)行,后跟任意數量的行(包括 0)只包含 0 個或多個空格,后跟一個(可能為空)線。 雖然這適用於正則表達式解析具有 2 個 <text> 行的單個示例條目的原始問題,但該文件可能包含許多條目。 通過參考最后包含 \\r\\n\\r\\n 的原始(並且可能有效)C# 版本,看起來 <text> 可以有任意數量的行,並且條目由空行分隔。 這也可以解釋使用“懶惰”模式 [\\s\\S]*?\\r\\n\\r\\n 來捕獲 <text> 直到(並包括)下一個空行而不是捕獲所有內容最后一個空行(貪婪的 [\\s\\S]*\\r\\n\\r\\n)。

因此,“工作代碼”模式可能應該是:

  (?<sequence>\d+)\r\n(?<start>\d{2}:\d{2}:\d{2},\d{3}) --> (?<end>\d{2}:\d{2}:\d{2},\d{3})\r\n(?<text>[\s\S]*?\r\n\r\n)

IE 只是 C# 版本,沒有轉義:或 >。 因此,cool25 犯的基本錯誤是將測試字符串存儲在 powershell here-string 中,從而對其進行更改,使其不再代表要解析的實際數據。 這里的教訓(除了實際的編程)是,在為例程創建測試數據時,請確保測試數據的來源與實際數據的來源盡可能相似。 在這種情況下,由於該例程旨在處理包含多個條目的文件,因此最好的測試數據應該是包含一個條目的文件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM