【问题标题】:Specify length (padding) of each column in a csv指定 csv 中每一列的长度(填充)
【发布时间】:2020-02-18 18:21:43
【问题描述】:

我正在尝试重新排列文件以匹配 BACS 银行格式。为了使它工作,下面的 csv 中的列需要具有特定的长度。我已经弄清楚 abcdabcd 列,因为它是一个重复模式(文件中还有几个),但是有几列具有我无法轻易定位的随机数。

有没有办法让我(理想情况下)根据其标题定位特定列,或者将所有内容定位到逗号以删除可能有用的东西? 在下面的示例文件中,您将看到值发生变化的三列。如果将所有内容定位到特定字符是解决方案,我正在考虑使用 .ljust 将列填充到指定长度(然后在 excel 中手动对其进行排序)。

原始文件

a,b,c,d,e,f,g,h,i,j,k
12345,1234567,0,11,123456,12345678,1234567,abcdabcd,A ABCD
123456,12345678,0,11,123456,12345678,12345678,abcdabcd,A ABCD
123456,1234567,0,11,123456,12345678,12345,abcdabcd,A ABCD
12345,1234567,0,11,123456,12345678,1234567,abcdabcd,A ABCD
123456,12345678,0,11,123456,12345678,123456789,abcdabcd,A ABCD

理想输出

a,b,c,d,e,f,g,h,i,j,k
123450,12345670,0,11,123456,12345678,123456700,abcdabcd,A ABCD
123456,12345678,0,11,123456,12345678,123456780,abcdabcd,A ABCD
123456,12345670,0,11,123456,12345678,123450000,abcdabcd,A ABCD
123450,12345670,0,11,123456,12345678,123456700,abcdabcd,A ABCD
123456,12345678,0,11,123456,12345678,123456789,abcdabcd,A ABCD

代码

with open('file.txt', 'r') as file :
  filedata = file.read()

filedata = filedata.replace('12345', '12345'.ljust(6, '0'))
with open('file.txt', 'w') as file:
  file.write(filedata)

编辑: 类似于 Python - How to add zeros to and integer/string? 的东西,但要么针对每个标题的特定列,要么至少针对第一个。

编辑2:

我正在使用以下内容重新排列我的列,是否可以对其进行修改以使用字符串长度?

import pandas as pd

## Read csv / tab-delimited in this example
df = pd.read_csv('test.txt', sep='\t')

## Reorder columns
df = df[['h','i','c','g','a','b','e','d','f','j','k']]

## Write csv / tab-delimited
df.to_csv('test', sep='\t')

【问题讨论】:

  • 您是否只是想填充一列以匹配最长的项目?您可以遍历行并保留最长匹配的索引,然后再次迭代以填充。
  • 嗨,西蒙,文件本身没有特定的顺序,新列从字符 1、7、15、18、24、32 等开始。我在这里要做的是确保例如,第一列的长度始终为 6 个字符,因此从 char 7 开始的第 2 列包含正确的信息。我的 csv 中有超过 1k 行,因此手动执行此操作将花费很长时间,但如果我什至可以定位第一列并确保其中的字符长度正确,我可以找到一种方法来完成这项工作。跨度>
  • 一个 csv 文件只是由逗号分隔的单词组成的行。 “列”基本上是行上某个索引处的所有字段。除非您的原始文件格式不同(您没有在问题中描述它),否则最简单的方法是逐行迭代。您还可以使用 pandas 等工具来操作 csv(maarten 的回答)。
  • 这是有道理的。该文件的格式与我的示例一样,只是由逗号分隔的文本和数字行,字符串的特定点包含相同的信息。

标签: python python-3.x csv


【解决方案1】:

使用pandas,您可以将列转换为str,然后使用.str.pad。您可以使用请求的长度制作一个 dict:

lengths = {
    "a": 6,
    "b": 8,
    "c": 3,
    "d": 6,
    "e": 8,
}

并像这样使用它:

result = pd.DataFrame(
    {
        column_name: column.str.pad(
            lengths.get(column_name, 0), side="right", fillchar="0"
        )
        for column_name, column in df.astype(str).items()
    }
)

如果 fillchar 每列不同,您也可以从 dict 中获取

【讨论】:

  • 我认为这是最接近我所追求的。我不确定如何准确地实现它(我目前正在使用熊猫来移动列,所以希望不会有那么不同)。感谢您将我推向正确的方向 Maarten。
【解决方案2】:
>>> print '{:0>5}'.format(4)
'00004'
>>> print '{:0<5}'.format(4)
'40000'
>>> print '{:0^5}'.format(4)
'00400'

例子:

#--------------DEFs------------------
def number_zero_right(number,len_number):
  return ('{:0<'+str(len_number)+'}').format(number)

#--------------MAIN------------------
a = 12345
b = 1234567
c = 0
d = 11
e = 123456
f = 12345678
g = 1234567
h = 'abcdabcd'
i = 'A'
j = 'ABCD'

print(a,b,c,d,e,f,g,h,i,j)
# > 12345 1234567 0 11 123456 12345678 1234567 abcdabcd A ABCD

a = number_zero_right(a,6)
b = number_zero_right(b,8)
c = number_zero_right(c,1)
d = number_zero_right(d,2)
e = number_zero_right(e,6)
f = number_zero_right(f,8)
g = number_zero_right(g,9)

print(a,b,c,d,e,f,g,h,i,j)
#> 123450 12345670 0 11 123456 12345678 123456700 abcdabcd A ABCD

【讨论】:

  • 这很好,但我的问题是数字不一样(应该在我的示例中更清楚地说明),否则我会使用 filedata.replace 和 .rjust 来解决它们。我可以以某种方式将 a、b、c、d 指定为字符串索引中的第 1、2、3 和第 4 项吗?这就是我基本上在寻找的(我认为)。
【解决方案3】:

设法到达那里,所以我想我会发布以防有人遇到类似问题。这仅适用于一列,但现在对我来说已经足够了。

#import pandas
import pandas as pd 

#open file and convert data to str  
data = pd.read_csv('Test.CSV', dtype = str) 

# width of output string 
width = 6

# fillchar
char ="_"

#Change the contents of column named ColumnID
data["ColumnID"]= data["ColumnID"].str.ljust(width, char) 

#print output  
print(data)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-30
    • 2012-10-30
    • 1970-01-01
    • 1970-01-01
    • 2016-12-04
    • 2016-06-12
    • 1970-01-01
    • 2018-04-11
    相关资源
    最近更新 更多