计算文本文件每行的制表符数目

本文关键字:制表符 文本 文件 计算 | 更新日期: 2023-09-27 18:04:29

在导入SQL Server之前,我试图验证在大型文本文件(8,000,000+行)中是否有正确的制表符数量。

我想我需要这样做:

int count = 0;
char tab = "'t";
foreach(char c in tab) 
{
    if(char.IsTab(c)) 
    {
        count++;
    }
}
然而,这是不正确的。我需要这样做来验证文件的格式是否正确。

计算文本文件每行的制表符数目

使用Linq,您可以得到这样的坏行:

using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
    public static void Main()
    {
        int expectedNumberOfTabs = 5;
        List<string> rows = new List<string>
        {
            "col1 't col2 't col3 't col4 't col5 't col6",
            "col1 't col2 't col3 't col4 't col5 't col6",
            "col1 't col2 't col3 't col4",
            "col1 't col2 't col3 't col4 't col5 't col6 't col7",
            "col1 't col2 't col3 't col4 't col5 't col6",
            "col1 't col2 't col3 't col4 't col5",
            "col1 't col2 't col3 't col4 't col5 't col6",
        };
        var badRows = rows.Where(row => row.Count(c => c == ''t') != expectedNumberOfTabs);
        foreach (var badRow in badRows)
        {
            // Fix the bad rows
            Console.WriteLine(badRow);
        }
    }
}

结果:

col1      col2      col3      col4
col1      col2      col3      col4      col5      col6      col7
col1      col2      col3      col4      col5

现在我不期望您一次将所有8,000,000+行读入内存。我想你应该一次一行地读取它们,一次一个地处理它们,所以你真正感兴趣的代码片段中的那行是:

row.Count(c => c == ''t') != expectedNumberOfTabs

它将识别"坏"行供您修复。

样本方法

因为您正在处理大量的数据,您可能想尝试将文件中的行复制到新文件中,并在遇到它们时修复错误行。一旦你有了新的"固定"文件,删除原始文件,然后将"固定"文件重命名为原始文件,并将其导入数据库。

using System.IO;
using System.Linq;
public class Program
{
    public static void Main()
    {
        int expectedNumberOfTabs = 5;
        string originalFile = "MyFile.txt";
        string originalFileFixed = "MyFileFixed.txt";
        using (StreamReader sr = new StreamReader(originalFile))
        using (StreamWriter sw = new StreamWriter(originalFileFixed))
        {
            string line = sr.ReadLine();
            if (line.Count(c => c == ''t') != expectedNumberOfTabs)
            {
                // line = ...Fix the line
            }
            sw.WriteLine(line);
        }
        // Delete original file
        File.Delete(originalFile);
        // Rename the fixed file back to the original file
        File.Move(originalFileFixed, originalFile);
        // Import the file
    }
}

对于如此大量的数据,您希望避免一次将整个文件加载到内存中。这里有一个解决方案,它只将文件的一行加载到内存中,并对该行中的制表符进行计数。结果保存到int[]中,其中数组中的每个项包含对应行上的制表符计数。

int[] counts = File.ReadLines("myfile.txt")
    .Select(l => l.Count(c => c == ''t'));

如果您只想要文件中所有选项卡的总数,那么您可以这样做:

int sum = File.ReadLines("myfile.txt")
    .Select(l => l.Count(c => c == ''t'))
    .Sum();

这似乎对我有用:

int count = 0;
string tab = "te'tst't't't";
foreach(char c in tab.ToCharArray()) 
{
    if (c == ''t')      // there is no char.IsTab() method
    {
        count++;
    }
}
Console.WriteLine(count);

给出如下结果:

4

你的原始代码不能工作,因为你将tab声明为char,不能迭代。我将其更改为string,并将string迭代为char s数组。

这可能不是最优的方式,但它是基于原始代码的工作方式。

如果你必须在上传之前这样做,你可以使用StreamReader,这样你就不会将整个文件加载到字符串中。但我想可能会很慢。也许你可以将文件分成相等的块,并让单独的线程处理它。

这是一个顺序的解决方案:

            int count = 0;
            using (StreamReader sr = new StreamReader(@"c:'temp'file.txt"))
            {
                count += sr.ReadLine().Count(f => f == ''t');
            }