计算每行文本文件的制表符数
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
迭代为 char
s.
的数组
这可能不是最佳方式,但它是一种基于您的原始代码的工作方式。
使用 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();
在导入到 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
迭代为 char
s.
这可能不是最佳方式,但它是一种基于您的原始代码的工作方式。
使用 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();