PowerShell拆分ICS日历事件及合并去重谷歌ICS文件问题求助
解决PowerShell处理ICS文件时无法将VEVENT作为多行字符串块的问题
你遇到的核心问题是默认Get-Content会把ICS文件拆成逐行的字符串数组,导致后续替换和分割操作都基于单行执行,没法得到完整的VEVENT多行块。我来帮你修正逻辑,同时给出合并两个ICS并去重的完整方案:
第一步:正确读取ICS文件为完整字符串
先避免逐行读取,用-Raw参数一次性把整个ICS文件读成单个字符串,这样后续正则操作才能处理多行内容:
# 读取第一个日历文件 $cal1Content = Get-Content ".\googlecalendar.ics" -Raw # 读取第二个日历文件 $cal2Content = Get-Content ".\another_calendar.ics" -Raw
第二步:提取所有VEVENT多行块
用正则表达式匹配从BEGIN:VEVENT到END:VEVENT的完整块,其中(?s)是单行模式(让.能匹配换行符),.*?是非贪婪匹配(确保每个匹配都是独立的事件):
# 从第一个日历提取事件块 $events1 = [regex]::Matches($cal1Content, '(?s)BEGIN:VEVENT.*?END:VEVENT') | ForEach-Object { $_.Value } # 从第二个日历提取事件块 $events2 = [regex]::Matches($cal2Content, '(?s)BEGIN:VEVENT.*?END:VEVENT') | ForEach-Object { $_.Value } # 合并两个日历的事件列表 $allEvents = $events1 + $events2
现在$allEvents里的每个元素都是完整的多行VEVENT事件字符串,你可以用$allEvents[0]验证,会输出整个事件的内容而非单行。
第三步:移除重复事件
ICS文件的UID字段是事件的唯一标识,我们通过它过滤重复项:
$seenUids = @() $uniqueEvents = $allEvents | Where-Object { # 提取当前事件的UID $uidMatch = $_ | Select-String '^UID:' -List if ($uidMatch) { $uid = $uidMatch.Line -replace '^UID:', '' # 若UID未被记录则保留事件,并标记该UID已见过 if ($seenUids -notcontains $uid) { $seenUids += $uid $true } else { $false } } else { # 无UID的事件直接保留(标准ICS一般都会有UID) $true } }
第四步:生成合并后的完整ICS文件
保留原ICS的头部信息(比如BEGIN:VCALENDAR、版本信息等),拼接去重后的事件,最后加上结尾:
# 提取第一个日历的头部(从开头到第一个VEVENT之前的内容) $header = $cal1Content -split '(?=BEGIN:VEVENT)', 2 | Select-Object -First 1 # 拼接成完整的日历内容 $mergedContent = $header + ($uniqueEvents -join "`r`n") + "`r`nEND:VCALENDAR" # 保存到新文件,用UTF-8编码避免乱码 $mergedContent | Out-File ".\merged_unique_calendar.ics" -Encoding UTF8
这样处理后,你就能得到合并两个日历且移除重复事件的ICS文件了。
内容的提问来源于stack exchange,提问作者umsrato




