在Python中修复csv文件行中的列数比其他行多的问题

l5tcr1uw  于 11个月前  发布在  Python
关注(0)|答案(1)|浏览(141)

我必须将一个Excel文件上传到Terrace中。所以我选择了需要上传的选项卡,并将其保存为CSV文件。(在多次尝试通过Terrace Studio GUI使用FastLoad失败后,我被建议使用Terrace BTEQ。)
问题:
1.某些行的列数多于其他行。
1.在使用BTEQ时,有些字符被误解。
1.我可以打印出一些计数,但我最终得到的错误
UnicodeDecodeError: 'charmap' codec can't decode byte ... in position ...: character maps to <undefined>我不知道该怎么办。
有人建议我使用Python来计算每行中的逗号/分隔符,以找到列太多的逗号/分隔符并修复它们,但每行有125,000行和66列。(这是非常脏的数据,是手动输入的,没有使用Excel的数据验证选项。)
如果我能只打印出需要修复的行的行号(而不是行号),并使用条件语句在现场修复它们,那就最好了。
我现在拥有的代码将打印文件路径,然后是新行中每行的列数,然后停止处理并返回UnicodeDecodeError。
代码:

with open('Data.csv', 'r') as csv_file:  
    for line in csv_file:  
        print( line.count(','))

字符串

tjrkku2a

tjrkku2a1#

我建议你从日志方法开始,有点像被建议的那样。如果“用条件语句当场修复它们”意味着停止阅读/导入这一行,让你在恢复阅读/导入之前以某种方式更改它.
你只需要打印出不符合预期的行,因为你认为数据包含66列,所以只需要打印出不符合预期的行。
对于应该有3列的CSV:

Col1,Col2,Col3
r1c1,r1c2
r2c1,r2c2,r2c3
r3c1
r4c1
r5c1
r6c1,r6c2,r6c3
r7c1,r7c2,r7c3
r8c1,r8c2
r9c1,r9c2

字符串
生成报告,如:

| Row # | N cols  |
| ----: | ------: |
|     1 |       2 |
|     3 |       1 |
|     4 |       1 |
|     5 |       1 |
|     8 |       2 |
|     9 |       2 |
import csv

N_COLS = 3

f_out = open("output_flat.csv", "w")
writer = csv.writer(f_out)
writer.writerow(["Row #", "N cols"])

# newline='' necessary if your fields have embedded newlines (good practice anyways)
f_in = open("input.csv", newline="")
reader = csv.reader(f_in)

next(reader)  # skip header

for i, row in enumerate(reader, start=1):
    if len(row) != N_COLS:
        writer.writerow([i, len(row)])

但对于更大的数据:

Col_1,Col_2,Col_3
r01c1,r01c2
r02c1,r02c2,r02c3
r03c1
r04c1
r05c1
r06c1,r06c2,r06c3
r07c1,r07c2,r07c3
r08c1,r08c2
r09c1,r09c2
r10c1,r10c2,r10c3
r11c1,r11c2,r11c3
r12c1,r12c2,r12c3
r13c1,r13c2,r13c3
r14c1,r14c2,r14c3
r15c1,r15c2,r15c3
r16c1
r17c1,r17c2
r18c1,r18c2
r19c1,r19c2
r20c1,r20c2
r21c1,r21c2
r22c1,r22c2,r22c3
r23c1,r23c2
r24c1,r24c2,r24c3
r25c1,r25c2
r26c1,r26c2,r26c3
r27c1,r27c2
r28c1,r28c2,r28c3
r29c1,r29c2
r30c1,r30c2
r31c1
r32c1,r32c2
r33c1
r34c1,r34c2,r34c3


尝试把坏的一面压缩成范围可能更有帮助,比如:

| N cols  | Row start | Row end |
| ------: | --------: | ------: |
|       2 |         1 |         |
|       1 |         3 |       5 |
|       2 |         8 |       9 |
|       1 |        16 |         |
|       2 |        17 |      21 |
|       2 |        23 |         |
|       2 |        25 |         |
|       2 |        27 |         |
|       2 |        29 |      30 |
|       1 |        31 |         |
|       2 |        32 |         |
|       1 |        33 |         |
f_out = open("output_ranges1.csv", "w")
writer = csv.writer(f_out)
writer.writerow(["N cols", "Row start", "Row end"])

def write_row(row: tuple[int, int, int]):
    """
    Write the col ct and the beg and end rows for the range with that col ct;
    unless beg and end are the same (one row), then just write beg row
    """
    if row[1] == row[2]:
        writer.writerow([row[0], row[1], ""])
    else:
        writer.writerow(row)

f_in = open("input.csv", newline="")
reader = csv.reader(f_in)

ncols = len(next(reader))

NO_TRACK = -1

tracking = False
row_num = NO_TRACK
cols_ct = NO_TRACK

i = 0  # scoped outside of loop, enumerate will increment

for i, row in enumerate(reader, start=1):
    _ncols = len(row)

    if _ncols != cols_ct:
        if tracking:
            write_row((cols_ct, row_num, i - 1))  # i-1 for prev row

        if _ncols == ncols:
            tracking = False
            row_num = NO_TRACK
            cols_ct = NO_TRACK
        else:
            tracking = True
            row_num = i
            cols_ct = _ncols

# flush final tracked range
if tracking:
    write_row((cols_ct, row_num, i))

相关问题