Golang文件清理功能支持

Golang文件清理功能支持 我有一个CSV文件看起来已损坏,因此我想进行一些清理。

我想先将其作为txt文件处理以进行清理,然后再作为CSV读取。

文件中有些字段包含"",有些则没有,并且注意到那些包含""的字段内部有,,例如:

有些数字显示为:"2,15.0,有些显示为22.3,不带""

有些文本显示为:Manager, Supply Chain,有些显示为Supervisor,不带""

我解决这个问题的方法是:

  1. 如果,位于""之间,则从文件中移除它
  2. 从文件中移除""

假设文件中的行如下:

John, supervisor, 20.22
Mark, "Manager, SC", "3,200.0"
Joseph, "Technician, Electrical", 15.2
"Selphia, Henry", "Manager, Lab", "4,250.0"

那么清理后的文件应该是:

John, supervisor, 20.22
Mark, Manager SC, 3200.0
Joseph, Technician Electrical, 15.2
Selphia Henry, Manager Lab, 4250.0

有什么想法或建议吗?


更多关于Golang文件清理功能支持的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

正则表达式是错误的解决方案。

更多关于Golang文件清理功能支持的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


非常感谢,我尝试了以下代码:

package main

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"regexp"
)

// https://yourbasic.org/golang/regexp-cheat-sheet/
func main() {
	// str1 := `"Selphia, Henry", "Manager, Lab", "4,250.0"` // {}
	input, err := ioutil.ReadFile("sample.csv")
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	re := regexp.MustCompile(`"\s*,\s*"|,\s*"|",\s*`)
	str := re.ReplaceAllString(string(input), `\t`) // `0x09`

	output := bytes.Replace([]byte(str), []byte(`"`), []byte(""), -1) // remove the `"` at begining and at end of each line
	if err = ioutil.WriteFile("modified.tsv", output, 0666); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fr, err := os.Open("modified.tsv")
	if err != nil {
		log.Fatal("Unable to open output")
	}
	//methods.FailOnError(err)
	defer fr.Close()
	rdr := csv.NewReader(fr)
	rdr.Comma = '\t'
	rows, err := rdr.ReadAll()
	if err != nil {
		log.Fatal("Unable to read data: ")
	}
	fmt.Printf("%s", rows[1])
}

输出结果是:

[Mark\tManager, SC\t3,200.0]

如果我尝试这样读取:

fmt.Printf("%s", rows[1][2])

我得到:

panic: runtime error: index out of range [2] with length 1

我有一个CSV文件看起来损坏了,所以我想做一些清理工作。 有什么想法吗?

清理时不要损坏数据!"Manager, SC" 应该变成 Manager, SC

请按步骤执行转换,并在每一步之后检查结果。

John, supervisor, 20.22
Mark, "Manager, SC", "3,200.0"
Joseph, "Technician, Electrical", 15.2
"Selphia, Henry", "Manager, Lab", "4,250.0"

.csv 文件当作 .txt 文件来读取。对于每一行,将不在引号 ('"') 内的逗号替换为制表符 ("\t" 或 0x09)。将转换后的输入 .csv 文件以 .tsv 作为扩展名写出。检查输出的 .tsv 文件。为了清晰可见,我在示例中将制表符 ("\t" 或 0x09) 显示为 \t

John\t supervisor\t 20.22
Mark\t "Manager, SC"\t "3,200.0"
Joseph\t "Technician, Electrical"\t 15.2
"Selphia, Henry"\t "Manager, Lab"\t "4,250.0"

读取 .tsv 文件。对于每个字段,修剪前导和尾随空格。如果字段的第一个和最后一个字符是引号 ('"'),则将其修剪掉。写出 .tsv 文件。检查输出的 .tsv 文件。

John\tsupervisor\t20.22
Mark\tManager, SC\t3,200.0
Joseph\tTechnician, Electrical\t15.2
Selphia, Henry\tManager, Lab\t4,250.0

读取 .tsv 文件。对于每个字段,如果移除逗号后 strconv.ParseFloat 返回 err == nil,则移除逗号。写出 .tsv 文件。检查输出的 .tsv 文件。

John\tsupervisor\t20.22
Mark\tManager, SC\t3200.0
Joseph\tTechnician, Electrical\t15.2
Selphia, Henry\tManager, Lab\t4250.0

对于 .tsv 文件,使用 encoding/csv 包:

rdr := csv.NewReader(file)
rdr.Comma = '\t'

在Go中处理这种CSV清理需求,可以使用标准库的encoding/csv配合自定义清理逻辑。以下是实现方案:

package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"strings"
)

func cleanCSV(inputPath, outputPath string) error {
	// 读取原始文件
	inputFile, err := os.Open(inputPath)
	if err != nil {
		return err
	}
	defer inputFile.Close()

	// 创建输出文件
	outputFile, err := os.Create(outputPath)
	if err != nil {
		return err
	}
	defer outputFile.Close()

	// 创建CSV读写器
	reader := csv.NewReader(inputFile)
	writer := csv.NewWriter(outputFile)
	defer writer.Flush()

	// 设置CSV读取选项
	reader.LazyQuotes = true
	reader.TrimLeadingSpace = true

	for {
		record, err := reader.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		// 清理每个字段
		cleanedRecord := make([]string, len(record))
		for i, field := range record {
			cleanedRecord[i] = cleanField(field)
		}

		// 写入清理后的记录
		if err := writer.Write(cleanedRecord); err != nil {
			return err
		}
	}

	return nil
}

func cleanField(field string) string {
	// 移除双引号
	field = strings.ReplaceAll(field, "\"", "")
	
	// 移除逗号(保留数字中的小数点)
	var result strings.Builder
	for _, r := range field {
		if r != ',' || (r == ',' && strings.Contains(field, ".")) {
			// 处理数字中的逗号:移除千位分隔符
			if r == ',' && strings.Contains(field, ".") {
				continue
			}
			result.WriteRune(r)
		}
	}
	
	return strings.TrimSpace(result.String())
}

func main() {
	// 示例使用
	err := cleanCSV("input.csv", "cleaned.csv")
	if err != nil {
		fmt.Printf("清理失败: %v\n", err)
		return
	}
	fmt.Println("文件清理完成")
}

如果需要更精确的数字处理,可以添加专门的数字清理函数:

func cleanNumericField(field string) string {
	// 移除所有非数字字符(除了小数点和负号)
	var result strings.Builder
	decimalFound := false
	
	for _, r := range field {
		switch {
		case r >= '0' && r <= '9':
			result.WriteRune(r)
		case r == '.' && !decimalFound:
			result.WriteRune(r)
			decimalFound = true
		case r == '-':
			result.WriteRune(r)
		}
	}
	
	return result.String()
}

对于混合类型字段的清理,可以使用类型检测:

func cleanMixedField(field string) string {
	// 移除双引号
	field = strings.ReplaceAll(field, "\"", "")
	
	// 检查是否为数字字段(包含逗号和小数点)
	if strings.Contains(field, ".") && strings.Contains(field, ",") {
		return cleanNumericField(field)
	}
	
	// 文本字段:移除所有逗号
	return strings.ReplaceAll(field, ",", "")
}

这个实现会正确处理你的示例数据,生成符合要求的清理后CSV文件。

回到顶部