跳到主要内容

csv-to-markdown-20261104

收藏0

本地离线 CSV 转 Markdown 表格工具,正确解析双引号包裹字段与字段内分隔符/换行,支持自定义分隔符、列对齐方式、无表头模式和结果写文件,全程不联网。

让 AI 安装

Mercury最新版本 0.1.0更新于 2026-11-04下载 0 次

scripts/Convert-CsvToMarkdown.ps1

4.7 KB
1#requires -Version 5.1
2<#
3.SYNOPSIS
4 将 CSV/TSV 文件转换为 Markdown 表格。
5.DESCRIPTION
6 自带 CSV 状态机解析器,支持双引号包裹字段、字段内分隔符与换行、"" 转义引号、
7 自定义分隔符、列对齐、无表头模式,可输出到屏幕或文件。全程离线。
8.PARAMETER InputFile
9 输入 CSV 文件路径(必填)。
10.PARAMETER Delimiter
11 字段分隔符,单字符,默认逗号。
12.PARAMETER Alignment
13 列对齐方式:left、center、right、none,默认 left。
14.PARAMETER NoHeader
15 第一行视为数据,自动生成 Column1、Column2 表头。
16.PARAMETER OutFile
17 结果写入指定文件(UTF-8 无 BOM);不传则输出到屏幕。
18.PARAMETER KeepWhitespace
19 保留字段首尾空白,默认去除。
20.EXAMPLE
21 .\Convert-CsvToMarkdown.ps1 -InputFile .\data.csv -OutFile .\table.md
22#>
23[CmdletBinding()]
24param(
25 [Parameter(Mandatory = $true)]
26 [string]$InputFile,
27
28 [ValidateLength(1, 1)]
29 [string]$Delimiter = ',',
30
31 [ValidateSet('left', 'center', 'right', 'none')]
32 [string]$Alignment = 'left',
33
34 [switch]$NoHeader,
35 [switch]$KeepWhitespace,
36 [string]$OutFile
37)
38
39Set-StrictMode -Version 2.0
40
41if (-not (Test-Path -LiteralPath $InputFile -PathType Leaf)) {
42 throw "找不到输入文件:$InputFile"
43}
44$text = [System.IO.File]::ReadAllText((Resolve-Path -LiteralPath $InputFile).Path)
45$delim = [char]$Delimiter
46
47# 解析整个 CSV 文本(状态机,支持引号内换行)
48function Parse-CsvText {
49 param([string]$Text, [char]$Delimiter)
50
51 $rows = New-Object System.Collections.Generic.List[object]
52 $row = New-Object System.Collections.Generic.List[string]
53 $field = New-Object System.Text.StringBuilder
54 $inQuotes = $false
55 $i = 0
56
57 while ($i -lt $Text.Length) {
58 $c = $Text[$i]
59
60 if ($inQuotes) {
61 if ($c -eq '"') {
62 if (($i + 1) -lt $Text.Length -and $Text[$i + 1] -eq '"') {
63 [void]$field.Append('"'); $i += 2; continue
64 }
65 $inQuotes = $false; $i++; continue
66 }
67 [void]$field.Append($c); $i++; continue
68 }
69
70 if ($c -eq '"') { $inQuotes = $true; $i++; continue }
71 if ($c -eq $Delimiter) {
72 $row.Add($field.ToString()); [void]$field.Clear(); $i++; continue
73 }
74 if ($c -eq "`r" -or $c -eq "`n") {
75 if ($row.Count -gt 0 -or $field.Length -gt 0) {
76 $row.Add($field.ToString()); [void]$field.Clear()
77 $rows.Add($row.ToArray())
78 $row = New-Object System.Collections.Generic.List[string]
79 }
80 if ($c -eq "`r" -and ($i + 1) -lt $Text.Length -and $Text[$i + 1] -eq "`n") { $i += 2 }
81 else { $i++ }
82 continue
83 }
84
85 [void]$field.Append($c); $i++
86 }
87
88 if ($row.Count -gt 0 -or $field.Length -gt 0) {
89 $row.Add($field.ToString())
90 $rows.Add($row.ToArray())
91 }
92 return $rows
93}
94
95$rows = Parse-CsvText -Text $text -Delimiter $delim
96if ($rows.Count -eq 0) {
97 throw '输入文件为空或没有可解析的数据行。'
98}
99
100# 计算最大列数,补齐短行
101$maxCols = 0
102foreach ($r in $rows) { if ($r.Count -gt $maxCols) { $maxCols = $r.Count } }
103for ($i = 0; $i -lt $rows.Count; $i++) {
104 if ($rows[$i].Count -lt $maxCols) {
105 $fixed = New-Object string[] $maxCols
106 for ($j = 0; $j -lt $maxCols; $j++) {
107 $fixed[$j] = if ($j -lt $rows[$i].Count) { $rows[$i][$j] } else { '' }
108 }
109 $rows[$i] = $fixed
110 Write-Warning "第 $($i + 1) 行字段数不足,已用空单元格补齐到 $maxCols 列。"
111 }
112}
113
114# 表头
115if ($NoHeader) {
116 $header = @(for ($j = 1; $j -le $maxCols; $j++) { "Column$j" })
117 $dataRows = $rows
118} else {
119 $header = $rows[0]
120 $dataRows = @($rows | Select-Object -Skip 1)
121}
122
123function Convert-EscapeCell {
124 param([string]$Value)
125 $v = $Value -replace "`r?`n", ' '
126 $v = $v.Replace('|', '\|')
127 if (-not $KeepWhitespace) { $v = $v.Trim() }
128 return $v
129}
130
131$separator = switch ($Alignment) {
132 'left' { ':---' }
133 'center' { ':---:' }
134 'right' { '---:' }
135 'none' { '---' }
136}
137
138$lines = New-Object System.Collections.Generic.List[string]
139$lines.Add('| ' + (($header | ForEach-Object { Convert-EscapeCell $_ }) -join ' | ') + ' |')
140$sepCells = @($separator) * $maxCols
141$lines.Add('| ' + ($sepCells -join ' | ') + ' |')
142foreach ($r in $dataRows) {
143 $lines.Add('| ' + (($r | ForEach-Object { Convert-EscapeCell $_ }) -join ' | ') + ' |')
144}
145
146$output = ($lines -join "`r`n")
147
148if ($OutFile) {
149 [System.IO.File]::WriteAllText($OutFile, $output, (New-Object System.Text.UTF8Encoding($false)))
150 Write-Output "已写入 $($lines.Count) 行 Markdown 到:$OutFile"
151} else {
152 Write-Output $output
153}

文件内容是平台检查时读出的文本,只供查看。平台不会运行包里的任何脚本或程序。