1

我有一个文件,其中的列如下所示:

Column1,Column2,Column3,Column4,Column5,Column6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
1,2,3,4,5,6
Column1,Column3,Column2,Column6,Column5,Column4
1,3,2,6,5,4
1,3,2,6,5,4
1,3,2,6,5,4
Column2,Column3,Column4,Column5,Column6,Column1
2,3,4,5,6,1
2,3,4,5,6,1
2,3,4,5,6,1

列在文件中间随机重新排序,知道顺序的唯一方法是查看数据之前的最后一组标题(Column1、Column2 等)(我还简化了数据以便更容易描绘。在现实生活中,无法区分数据,因为它们都是可以真正进入任何列的大整数值)

显然,在使用 BULK INSERT 时,这对 SQL Server 不是很友好,所以我需要找到一种方法来以与我的 SQL 数据库中表的列顺序相匹配的一致顺序排列所有列。最好的方法是什么?我听说 Python 是要使用的语言,但我从未使用过它。任何语言的任何建议/示例脚本都将受到赞赏。

4

3 回答 3

3

python中的解决方案:

我会逐行阅读并寻找标题。当我找到一个标题时,我用它来计算顺序(不知何故)。然后我将这个顺序传递给itemgetter它将执行重新排序元素的魔力:

from operator import itemgetter
def header_parse(line,order_dict):
    header_info = line.split(',')
    indices = [None] * len(header_info)
    for i,col_name in enumerate(header_info):
        indices[order_dict[col_name]] = i
    return indices

def fix(fname,foutname):
    with open(fname) as f,open(foutname,'w') as fout:
        #Assume first line is a "header" and gives the order to use for the
        #rest of the file
        line = f.readline()
        order_dict = dict((name,i) for i,name in enumerate(line.strip().split(',')))
        reorder_magic = itemgetter(*header_parse(line.strip(),order_dict))
        for line in f:
            if line.startswith('Column'):  #somehow determine if this is a "header"
                reorder_magic = itemgetter(*header_parse(line.strip(),order_dict))
            else:
                fout.write(','.join(reorder_magic(line.strip().split(','))) + '\n')

if __name__ == '__main__':
    import sys
    fix(sys.argv[1],sys.argv[2])

现在您可以将其称为:

python fixscript.py badfile goodfile
于 2012-10-23T19:09:58.697 回答
2

这可以通过两个步骤轻松解决:

  • 新标头开始时将文件拆分为多个文件
  • 使用 csv dict reader 读取每个文件,对键进行排序并以正确的顺序重新输出行

这是一个示例,您可以如何了解它,

def is_header(line):
    return line.find('Column') >= 0

def process(lines):  
    headers = None
    for line in lines:
        line = line.strip()
        if is_header(line):
            headers = list(enumerate(line.split(",")))
            headers_map = dict(headers)
            headers.sort(key=lambda (i,v):headers_map[i])
            print ",".join([h for i,h in headers])
            continue

        values = list(enumerate(line.split(",")))
        values.sort(key=lambda (i,v):headers_map[i])
        print ",".join([v for i,v in values])

if __name__ == "__main__":
    import sys
    process(open(sys.argv[1]))

您还可以更改功能is_header以在实际情况下正确识别标题

于 2012-10-23T19:03:21.987 回答
2

由于您没有提到具体问题,我将假设您在提出算法时遇到问题。

  1. 对于每一行,

    1. 将行解析为字段。
    2. 如果是第一个标题行,

      1. 输出标题。
      2. 创建要定位的字段名称映射。

        %map = map { $fields[$_] => $_ } 0..$#fields;
        
      3. 创建原始位置到新位置的地图。

        @map = @map{ @fields };
        
    3. 如果它是第一个以外的标题行,

      1. 将原始位置的地图更新为新位置。

        @map = @map{ @fields };
        
    4. 如果不是标题行,

      1. 重新排序字段。

        @fields[ @map ] = @fields;
        
      2. 输出行。

(片段在 Perl 中。)

于 2012-10-23T19:18:11.353 回答