Python 2.7匹配CSV文件行中的精确字符串

时间:2017-06-22 14:15:23

标签: python string python-2.7 match

我有一个csv文件,其中包含特定列中的字符串以及其他列中的其他值。我还有一个字符串列表。 循环遍历行,我想检查列表中的一个字符串是否完全包含在csv文件的行中。 如果是,则必须将此行写入新的csv文件中。

csv文件是一个行列表,如:

22/06/2017 04:00:32 | string1 | value1   
22/06/2017 04:00:32 | string11 | value2    
22/06/2017 04:00:32 | string2 | value3   
22/06/2017 04:00:32 | string3 | value4

我编写了这段代码,它运行正常,但它没有考虑字符串的“精确”匹配。

import os, csv

def filter_csv(folderpath):

     list1 = [
     ('name1',1,'string1','value1'),
     ('name2',2,'string2','value2'),
     ('name3',3,'string3','value3'),
     ('name4',4,'string4','value4'),
     ...
     ]

     def column(matrix, i):
         return [row[i] for row in matrix]

     col = column(list1,2)

     for file in os.listdir("%s" % folderpath):
         if file.endswith(".csv"):
             new_file = 'new_'+file
             filepath = os.path.join("%s" % folderpath, file)
             new_filepath = os.path.join("%s" % folderpath, new_file)

             with open('%s' % filepath) as csvfile:
                 lines = csvfile.readlines()

             with open('%s' % new_filepath, 'wb') as csvfile2:
                 for line in lines:
                     for namevar in col:
                         if namevar in line:
                             csvfile2.write(line)

     return

如何为csv文件的列添加完全匹配的字符串?

2 个答案:

答案 0 :(得分:1)

您要做的是将过滤后的列表写入文件。

过滤条件是"某些预定义的有效值之一必须出现在CSV行" 上,我们可以使用集合交集。我们需要一组有效值,当你与当前输入行相交时,有些值保留,然后当前输入行通过。

import os, csv
from glob import glob

def filter_csv(folderpath):

    list1 = [
        ('name1',1,'string1','value1'),
        ('name2',2,'string2','value2'),
        ('name3',3,'string3','value3'),
        ('name4',4,'string4','value4'),
        # ...
    ]

    # prepare a set of valid values
    valid_values = {row[2] for row in list1}

    for filepath in glob("%s/*.csv" % folderpath):
        filename = os.path.basename(filepath)
        new_filepath = os.path.join(folderpath, 'new_' + filename)

        with open(filepath, newline='') as infile, \
            open(new_filepath, 'wb') as outfile:

            reader = csv.reader(infile)
            writer = csv.writer(outfile)
            filtered_rows = (row for row in reader if valid_values.intersection(row))

            writer.writerows(filtered_rows)

备注

  • glob()对于按扩展名查找文件非常有用
  • with可以处理多个资源
  • 您可以使用\跨越多行
  • 集合已针对查找匹配值进行了优化
  • { ... }是一种集合理解 - 它将列表转换为集合
  • 始终使用CSV模块解析CSV文件 - 绝不使用.split()或类似的内容

答案 1 :(得分:0)

只是为了使用不同的库提供一个略有不同的解决方案,现在我认为它可能有点过分,但你可能会喜欢它:)你应该能够修改示例以插入到你的代码中......

import pandas as pd

# Dummy col
col = ["string1", "string2", "string3"]

# Read in CSV file
df = pd.read_csv("test.csv", header=None, skipinitialspace=True, delimiter ="|")

# Strip all strings so that trailing whitespace is ignored. 
# csv library OP used would also be "fooled" by whitepace
df_obj = df.select_dtypes(['object'])
df[df_obj.columns] = df_obj.apply(lambda x: x.str.strip())

# Select only rows with any column that has a value in col
df = df[df.isin(col).any(axis=1)]

# Write out CSV to new file
df.to_csv("test2.csv")

这将通过检查每列中col中的一个值来过滤CSV的每一行。如果任何列的值为col,则它会显示在输出CSV文件中。

我发现的一件事是,如果CSV中的文本有尾随空格,那么完全匹配就不会起作用。例如,由于尾随空格,string1下方的CSV行不会完全匹配。

 value1, value2, string1   , value3

因此,修剪所有字符串的额外代码。使用csv库进行测试,它会遇到同样的问题。如果您知道您的CSV字符串永远不会有尾随空格,那么您甚至可以删除这两行。然后,以完整形式过滤的代码将是(借用Tomalak's use of glob):

import pandas as pd
import glob
import os

def filter_csv(folderpath):

    list1 = [
        ('name1',1,'string1','value1'),
        ('name2',2,'string2','value2'),
        ('name3',3,'string3','value3'),
        ('name4',4,'string4','value4')
    ]

    def column(matrix, i):
        return [row[i] for row in matrix]

    col = column(list1,2)

    for filepath in glob.glob("%s/*.csv" % folderpath):
        filename = os.path.basename(filepath)
        new_filepath = os.path.join(folderpath, 'new_' + filename)
        df = pd.read_csv(filename, header=None, skipinitialspace=True, delimiter ="|")
        df_obj = df.select_dtypes(['object'])
        df[df_obj.columns] = df_obj.apply(lambda x: x.str.strip())
        df[df.isin(col).any(axis=1)].to_csv(new_filepath, sep="|", header=False, index=False)

但如果空格不是问题,您可以修改代码中的以下行:

 df_obj = df.select_dtypes(['object'])
 df[df_obj.columns] = df_obj.apply(lambda x: x.str.strip())