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

Count number of tabs per line of text file

在导入到 SQL 服务器之前,我正在尝试验证大型文本文件(8,000,000 多行)中的制表符数量是否正确。

我想我需要做这样的事情:

int count = 0;
char tab = "\t";
foreach(char c in tab) 
{
    if(char.IsTab(c)) 
    {
        count++;
    }
}

然而,这是不正确的。我需要这样做来验证文件的格式是否正确。

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

这是一个顺序解决方案:

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

这似乎对我有用:

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 迭代为 chars.

的数组

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

使用 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

这将确定一个 "bad" 行供您修复。

示例方法

因为您要处理大量数据,所以您可能想尝试将文件中的行复制到新文件中,并在 运行 中修复坏行。获得新的 "fixed" 文件后,删除原始文件,然后将 "fixed" 文件重命名回原始文件并将其导入数据库。

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();