将 C# 代码转换为 powershell:scriptblock-delegate
本文关键字:powershell scriptblock-delegate 转换 代码 | 更新日期: 2023-09-27 18:03:30
这是我想要转换为"PowerShell Way"的代码:
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)
但它不起作用。谢谢你的帮助。
我知道我必须使用脚本块委托来达到我的目的。
你在这里遇到了几个问题。 这是一个有效的版本:
$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 用单个 ' 表示 here-string 中的行尾。
此外,如上所述,字符串末尾没有 ',因为 here-string 的末尾由 ''@ 标记(即行首的 '@(,因此最后一个 ' 是结束标记的一部分,而不是字符串。
不幸的是,仅删除无关的 ''r 和 ' 字符转义是行不通的。如果没有具体的匹配来定义<文本>的结束位置,[''s''S]*?将匹配为空(让整个模式成功的最小匹配(。若要匹配所有<文本>请使用 [''s''S]*(贪婪版本(或使用 [''s''S]*?$ 强制匹配到字符串的末尾。文本>文本>
此外,: 和> 不是元字符(如 . 或 *(,因此不需要转义(尽管它没有伤害(。基思·希尔(Keith Hill(修复了这个问题,但没有提及。此外,指定多行选项标志 (?m( 没有任何用途,因为原始模式没有受影响的锚点(^ 和 $(,并且 C# 版本无论如何都没有设置它。即使
(?<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'作为行尾标记。
虽然我会说 Keith Hill 使用 ''s*$''s* 匹配行尾的答案更健壮,因为它匹配 ' 和 ''r'(以及任何后续或尚未匹配的前一个空格(,但如果文件的结构是已知且固定的,那么使用无界量词来匹配固定部分可能会导致细微的错误。在这种情况下,使用 ''s*$''s* 匹配
任意数量的行(包括 0(,该行仅包含 0 个或多个空格,后跟一个(可能为空的(行。虽然这适用于正则表达式解析具有 2 <文本>行的单个示例条目的原始问题,但该文件可能包含许多条目。通过引用末尾包含 ''r'''r' 的原始(可能有效(C# 版本,似乎
因此,"工作代码"模式可能应该是:
(?<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)
即只是 C# 版本,无法转义 : 或>。因此,cool25 犯的基本错误是将测试字符串存储在 powershell here 字符串中,从而对其进行更改,使其不再表示要解析的实际数据。这里的教训(除了实际编程之外(是,在为例程创建测试数据时,请确保测试数据源尽可能与实际数据源相似。在这种情况下,由于例程旨在处理包含多个条目的文件,因此最好的测试数据将是一个条目的文件。