You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为制表符分隔文件的无表头列赋值并实现列交换

解决无表头列识别与列交换问题

首先,我们先明确你的需求:源文件前几列是有明确表头的(比如Barcode1、Plate #、日期列),末尾是重复的无表头列组(比如示例里的A 1 4 5 6重复多次),需要识别这些无表头列并完成指定列的交换。

核心思路

  1. 区分有表头/无表头列范围:通过你已经实现的dataHeaders列表长度,确定有表头列的总数,剩下的就是无表头列。
  2. 利用固定格式定位无表头列:因为源文件格式固定,我们可以预先定义无表头列组的大小(比如示例中每组是5列:A 1 4 5 6),然后通过「组索引+组内列索引」来定位具体的无表头列。
  3. 扩展列索引获取逻辑:支持同时获取表头列和无表头列的索引。

修改后的完整代码

# 定义要交换的列:支持表头列(type=header)和无表头列(type=no-header)
$swapColumns = @{
    column1 = @{ type = "header"; name = "date-header"; instance = 1 }
    column2 = @{ type = "no-header"; groupIndex = 1; columnInGroup = 0; groupSize = 5 } 
    # 解释:第2个无表头组(索引从0开始)的第1列(索引从0开始),每组5列
}
$formats = @( 'XR-{0:yyyyMMdd}-01.txt' )
$date = [datetime]::now
$ErrorActionPreference = 'Stop'

# 获取表头列的索引
function Get-HeaderIndex {
    param(
        [System.Collections.Generic.List[string]]$Source,
        [string]$Header,
        [uint16]$Instance
    )
    $index = 0;
    for ($i = 0; $i -lt $Instance; $i++) {
        $index = $Source.IndexOf($Header, $index, ($Source.Count - $index))
        if (($index -eq -1) -or (($i + 1) -eq $Instance)) {
            break
        }
        $index = $index + 1
    }
    if ($index -eq -1) {
        throw "表头 '$Header' 的第 $Instance 次出现未找到"
    }
    return $index
}

# 获取无表头列的索引
function Get-NoHeaderColumnIndex {
    param(
        [int]$HeaderColumnCount, # 有表头列的总数
        [int]$GroupIndex,        # 无表头组的索引(从0开始)
        [int]$ColumnInGroup,     # 组内列的索引(从0开始)
        [int]$GroupSize          # 每个无表头组的列数
    )
    $calculatedIndex = $HeaderColumnCount + ($GroupIndex * $GroupSize) + $ColumnInGroup
    return $calculatedIndex
}

# 获取目标文件
$fileDetails = Get-ChildItem $PSScriptRoot\UCX-*.txt | Select-Object -First 1
$file = Get-Content $fileDetails

# 解析文件中的各个 section
$sections = @()
for ($i = 0; $i -lt $file.Count; $i++) {
    if ($file[$i] -match '^=+(\w+)=+$') {
        $sections += [pscustomobject]@{line = $i; header = $Matches[1]}
    }
}

# 获取data section和下一个section的位置
$dataSection = $sections | Where-Object {$_.header -eq 'data'}
$nextSection = $sections | Where-Object {$_.line -gt $dataSection.line} | Sort-Object -Property line | Select-Object -First 1

# 解析data表头,将日期格式的表头统一标记为'date-header'
$dataHeaders = New-Object System.Collections.Generic.List[string]
$file[$dataSection.line + 1].Split("`t") | ForEach-Object {
    $headerTrimmed = $_.Replace('EST','').Trim()
    $headerDateValue = [datetime]::MinValue
    $headerIsDate = [datetime]::TryParse($headerTrimmed, [ref]$headerDateValue)
    if ($headerIsDate) {
        $dataHeaders.Add('date-header')
    } else {
        $dataHeaders.Add($headerTrimmed)
    }
}

# 获取要交换的两个列的索引
# 处理第一列
if ($swapColumns.column1.type -eq "header") {
    $column1 = Get-HeaderIndex -Source $dataHeaders -Header $swapColumns.column1.name -Instance $swapColumns.column1.instance
} else {
    $column1 = Get-NoHeaderColumnIndex -HeaderColumnCount $dataHeaders.Count `
        -GroupIndex $swapColumns.column1.groupIndex `
        -ColumnInGroup $swapColumns.column1.columnInGroup `
        -GroupSize $swapColumns.column1.groupSize
}

# 处理第二列(修正了原代码中缺失$符号的错误)
if ($swapColumns.column2.type -eq "header") {
    $column2 = Get-HeaderIndex -Source $dataHeaders -Header $swapColumns.column2.name -Instance $swapColumns.column2.instance
} else {
    $column2 = Get-NoHeaderColumnIndex -HeaderColumnCount $dataHeaders.Count `
        -GroupIndex $swapColumns.column2.groupIndex `
        -ColumnInGroup $swapColumns.column2.columnInGroup `
        -GroupSize $swapColumns.column2.groupSize
}

# 遍历数据行,交换指定列
for ($i = $dataSection.line + 2; $i -lt $nextSection.line - 1; $i++) {
    $line = $file[$i]
    $parts = $line.Split("`t") # 如果有空列可以加参数:[System.StringSplitOptions]::RemoveEmptyEntries
    
    # 交换列数据
    $temp = $parts[$column1]
    $parts[$column1] = $parts[$column2]
    $parts[$column2] = $temp
    
    $file[$i] = $parts -join "`t"
}

# 输出新文件
$formats | ForEach-Object {
    $file | Out-File ($_ -f $date) -Force -Encoding utf8 # 指定编码避免乱码问题
}

关键修改说明

  1. 扩展swapColumns定义:新增type字段区分表头列和无表头列,无表头列需要指定groupIndex(组序号)、columnInGroup(组内列序号)和groupSize(每组列数)。
  2. 新增Get-NoHeaderColumnIndex函数:根据有表头列总数、组索引和组内列索引计算无表头列的具体位置。
  3. 修正原代码错误:原代码中Get-HeaderIndex -Header swapColumns.column2.name缺失$符号,已修正为$swapColumns.column2.name。
  4. 优化细节:添加了错误提示信息、指定文件编码避免乱码问题。

使用注意事项

  • 根据你的实际文件调整$swapColumns中的参数,特别是无表头列的groupSize(必须和源文件中每组无表头列的列数一致)。
  • 索引均从0开始计数,比如groupIndex=1代表第2个无表头组。

内容的提问来源于stack exchange,提问作者Johnnyc

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:58:39