csv 查找和替换不更新值

a14dhokn  于 2022-12-06  发布在  其他
关注(0)|答案(1)|浏览(183)

我正在写一个脚本,将csv组合成一个,然后为特定格式查找替换,并要求用户更正不匹配的格式。

import glob
import re
import csv

read_files = glob.glob("*.txt")
final_file = 'TABS3.ASC'
strformat1 = re.compile(r'\d{3}\.\d{5}')

#combine all files into one
with open(final_file, "wb") as outfile:
    for f in read_files:
        with open(f, "rb") as infile:
            outfile.write(infile.read())

#read new file and check for matching string
with open(final_file, newline='') as fin:
      
           
    check = list(csv.reader(fin))
    for row in check:        
        if strformat1.match(row[0]):
            pass
        else:
            show = print (row[0])
            find = row[0]
            replace = input ('How do you want to change: ')
            check = ''.join(str(i) for i in check) \
            .replace(str(find), str(replace))
            with open(final_file, "w") as final:
                final.write(check)

输出不是正确的csv格式

['710.00501', '79', '1', 'L140', 'A110', '10/10/2022', '0.60', '', '', ""]['774.00006', '79', '1', 'L160', 'A103', '10/10/2022', '0.50', '', '', '']['714.00150', '79', '1', 'L140', 'A110', '10/10/2022', '4.00', '', '', '']

应该是

"710.00501", "79", "1", "L140", "A110", "10/10/2022", "0.60", "", "", ""
"774.00006", "79", "1", "L160", "A103", "10/10/2022", "0.50", "", "", ""
"714.00150", "79", "1", "L140", "A110", "10/10/2022", "4.00", "", "", ""
k3bvogb1

k3bvogb11#

这个问题有很多不同的部分,你已经做了很好的尝试:)
我建议将问题分解为三个不同的步骤和代码块:
1.读取所有txt文件作为CSV,并将每组行添加到所有行的列表中。
1.迭代所有行并根据需要进行修改。
1.最后,以CSV格式写出所有行。
它给我的好处是能够打印出数据,并可视化刚刚发生的事情;它还可以减少代码的缩进并使代码更易于阅读。
我模拟了三个非常小的输入TXT文件的基础上的数据在您的职位:

input1.txt
==========
710.00501,79,1,L140,A110,10/10/2022,0.60,,,
999.44,22,2,Z333,Y111,10/10/2022,0.66,,,

input2.txt
==========
774.00006,79,1,L160,A103,10/10/2022,0.50,,,

input3.txt
==========
714.00150,79,1,L140,A110,10/10/2022,4.00,,,

我还添加了一行与正则表达式不匹配的代码,以练习第2步中的代码。

获取所有行

我说“as CSV”是因为我看到您将文件作为文本打开以收集所有行;也可以作为文本来写出一行。这可能可行,但是如果文件没有一个合适的,最后的换行符,那么你最终会把当前文件的最后一行和下一个文件的第一行合并起来,比如:

999.44,22,2,Z333,Y111,10/10/2022,0.66,,,774.00006,79,1,L160,A103,10/10/2022,0.50,,,

在类似CSV的文件上使用csv读取器/写入器总是更安全:他们将看到并尊重不同的 * 数据行 *,而不是仅仅 * 文本行 *。

all_rows = []
for fname in glob.glob("input*.txt"):
    with open(fname, newline="") as f:
        reader = csv.reader(f)
        all_rows.extend(list(reader))

pprint.pprint(all_rows)

csv文档建议在所有阅读示例中使用newline="”。
运行它,我们可以看到所有行:

[['710.00501', '79', '1', 'L140', 'A110', '10/10/2022', '0.60', '', '', ''],
 [   '999.44', '22', '2', 'Z333', 'Y111', '10/10/2022', '0.66', '', '', ''],
 ['774.00006', '79', '1', 'L160', 'A103', '10/10/2022', '0.50', '', '', ''],
 ['714.00150', '79', '1', 'L140', 'A110', '10/10/2022', '4.00', '', '', '']]

这个打印输出还帮助我们形象地看到csv阅读器把一行看作一个字符串列表; all_rows是字符串列表的列表。
接下来,处理像“999.44”这样的数据。

有选择地修改行

我不太清楚你想用join()语句和replace变量做什么。下面的代码展示了如何只修改与正则表达式不匹配的行的第一列。
我喜欢检查一行是否符合某个条件,这意味着我应该忽略它,然后使用continue关键字跳到下一行;它删除了一级缩进,并避免了else语句,我通常认为这是更可取的:

num_re = re.compile(r"\d{3}\.\d{5}")

for row in all_rows:
    some_num = row[0]
    if num_re.match(some_num):
        continue

    change = input(f"\n'{some_num}' doesn't match, change it to: ")

    row[0] = change.strip()

print()
pprint.pprint(all_rows)

运行该命令,我可以将“999.44”更改为“999.44009”(同样,不确定这是否是您实际需要的):

'999.44' doesn't match, change it to: 999.44009

[['710.00501', '79', '1', 'L140', 'A110', '10/10/2022', '0.60', '', '', ''],
 ['999.44009', '22', '2', 'Z333', 'Y111', '10/10/2022', '0.66', '', '', ''],
 ['774.00006', '79', '1', 'L160', 'A103', '10/10/2022', '0.50', '', '', ''],
 ['714.00150', '79', '1', 'L140', 'A110', '10/10/2022', '4.00', '', '', '']]

如果你想替换整行中每一列的某段数据,我会对每一列使用传统的for循环:

for i, col in enumerate(row):
    row[i] = col.replace("foo", "bar")

这很容易阅读和纠正。

写入所有行

我们已经能够在每一步可视化数据,并确保其正确性。现在,只需几行代码就可以将其写出来:

with open("output.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(all_rows)

我的输出.csv如下所示:

710.00501,79,1,L140,A110,10/10/2022,0.60,,,
999.44009,22,2,Z333,Y111,10/10/2022,0.66,,,
774.00006,79,1,L160,A103,10/10/2022,0.50,,,
714.00150,79,1,L140,A110,10/10/2022,4.00,,,

把所有的一切放在一起,最后的想法
如果没有所有的debug-print语句,解决问题看起来相当简洁:

all_rows = []
for fname in glob.glob("input*.txt"):
    with open(fname, newline="") as f:
        reader = csv.reader(f)
        all_rows.extend(list(reader))

num_re = re.compile(r"\d{3}\.\d{5}")

for row in all_rows:
    some_num = row[0]
    if num_re.match(some_num):
        continue

    change = input(f"\n'{some_num}' doesn't match, change it to: ")

    row[0] = change.strip()

with open("output.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerows(all_rows)

我也看到你这样做在你的尝试:

...
check = list(csv.reader(fin))
for row in check:
    ...

我们可以在读取器上使用list()函数来获取所有行,以便以后处理,就像我们对all_rows所做的那样。如果我们只想一次一行地遍历每一行(而不是将每一行都保存在内存中),我们可以直接在读取器上使用for循环:

reader = csv.reader(fin)
for row in reader:
    ...

相关问题