繁体   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