Как вы динамически идентифицируете неизвестные разделители в файле данных? - PullRequest
12 голосов
/ 17 октября 2010

У меня есть три файла входных данных.Каждый использует свой разделитель для данных, содержащихся в нем.Файл данных один выглядит так:

apples | bananas | oranges | grapes

Файл данных два выглядит так:

quarter, dime, nickel, penny

Файл данных три выглядит так:

horse cow pig chicken goat

(изменение количества столбцов также является преднамеренным)

У меня была мысль посчитать количество не-буквенных символов и предположить, что наибольшее количество было символом разделителя.Однако файлы с разделителями без пробелов также имеют пробелы до и после разделителей, поэтому пробелы выигрывают во всех трех файлах.Вот мой код:

def count_chars(s):
    valid_seps=[' ','|',',',';','\t']
    cnt = {}
    for c in s:
        if c in valid_seps: cnt[c] = cnt.get(c,0) + 1
    return cnt

infile = 'pipe.txt' #or 'comma.txt' or 'space.txt'
records = open(infile,'r').read()
print count_chars(records)

Он напечатает словарь с количеством всех допустимых символов.В каждом случае пространство всегда выигрывает, поэтому я не могу рассчитывать на это, чтобы сказать мне, что такое разделитель.

Но я не могу придумать лучшего способа сделать это.

Есть предложения?

Ответы [ 3 ]

66 голосов
/ 17 октября 2010

Как насчет попробовать стандарт Python CSV: http://docs.python.org/library/csv.html#csv.Sniffer

import csv

sniffer = csv.Sniffer()
dialect = sniffer.sniff('quarter, dime, nickel, penny')
print dialect.delimiter
# returns ','
5 голосов
/ 17 октября 2010

Если вы используете python, я бы предложил просто вызвать re.split на строке со всеми допустимыми ожидаемыми разделителями:

>>> l = "big long list of space separated words"
>>> re.split(r'[ ,|;"]+', l)
['big', 'long', 'list', 'of', 'space', 'separated', 'words']

Единственная проблема была бы, если один из файлов использовал разделитель как часть данных.

Если вам необходимо определить разделитель, лучше всего считать все, кроме пробелов. Если вхождений почти нет, то это, вероятно, пробел, в противном случае это максимум отображаемых символов.

К сожалению, действительно нет никакого способа быть уверенным. У вас могут быть данные, разделенные пробелами, запятые, или у вас может быть | разделенные данные заполняются точкой с запятой. Это может не всегда работать.

1 голос
/ 18 октября 2010

Я закончил с регулярным выражением из-за проблемы пробелов. Вот мой законченный код, на случай, если кто-то заинтересован или может использовать в нем что-то еще. С одной стороны, было бы неплохо найти способ динамического определения порядка столбцов, но я понимаю, что это немного сложнее. А пока я прибегаю к старым трюкам, чтобы разобраться с этим.

<code>for infile in glob.glob(os.path.join(self._input_dir, self._file_mask)):
            #couldn't quite figure out a way to make this a single block 
            #(rather than three separate if/elifs. But you can see the split is
            #generalized already, so if anyone can come up with a better way,
            #I'm all ears!! :)
            for row in open(infile,'r').readlines():
                if infile.find('comma') > -1: 
                    datefmt = "%m/%d/%Y"
                    last, first, gender, color, dobraw = \
                            [x.strip() for x in re.split(r'[ ,|;"\t]+', row)]
                elif infile.find('space') > -1: 
                    datefmt = "%m-%d-%Y"
                    last, first, unused, gender, dobraw, color = \
                            [x.strip() for x in re.split(r'[ ,|;"\t]+', row)]<br>
                elif infile.find('pipe') > -1:
                    datefmt = "%m-%d-%Y"
                    last, first, unused, gender, color, dobraw = \
                            [x.strip() for x in re.split(r'[ ,|;"\t]+', row)]
                    #There is also a way to do this with csv.Sniffer, but the 
                    #spaces around the pipe delimiter also confuse sniffer, so
                    #I couldn't use it.
                else: raise ValueError(infile + "is not an acceptable input file.")
                
...