Обробляти просто текстові дані


0

У мене є цей звичайний текстовий файл, який мені потрібно автоматично перевірити, а результати записати в інший звичайний текстовий файл. Зауважте, що я буду використовувати звичайний текст та CSV взаємозамінно, оскільки CSV - це звичайний текст із загальним роздільником між даними (коми, вкладки тощо).

Приклади даних

ABD-01A
ABD-01B
ABD-01C
AL-25A
AL-25B

Перший процес - розпізнайте перші два розділи даних ( text- number), щоб повторити та порахувати їх у вихідному CSV:

ABD-01,1
ABD-01,2
ABD-01,3
AL-25,1
AL-25,2

Процес другий - перша частина зібраних вище даних має вид первинного ключа, призначеного їм у іншому файлі. Я також хотів би отримати первинні ключі, згадані в новоспечених файлах:

#primary key file
1,ABD-01
2,ABD-02
3,AL-02
20,AL-25

#newly generated file
1,ABD-01,1
1,ABD-01,2
1,ABD-01,3
20,AL-25,1
20,AL-25,2

Тому, в основному, я запитую її, чи є якесь програмне забезпечення, яке могло б мені допомогти з цим в Windows або Linux-операційних системах. Bash може допомогти мені з більш простою обробкою, але я не думаю, що він може впоратися з цим. Порадьте, будь ласка.


Чи можуть одні і ті ж дані траплятися кілька разів в одному файлі? (Наприклад, " , , " ...)ABD-01AABD-01BAL-25AABD-01A
grawity

@grawity Ні, всі дані унікальні.
Oxwivi

У цьому випадку ви можете використовувати приклади сценаріїв, які я надав у своєму іншому коментарі. (Обидва роблять те саме, але написані різними мовами, щоб можна було порівняти.)
grawity

Відповіді:


1
  1. Виберіть бажану мову - Perl добре працює з текстом; Python, PHP і Ruby все в порядку, якщо трохи повільніше.
  2. Спочатку прочитайте ключовий файл:
    • розділити кожен key,dataрядок на keyі data,
    • тоді зберігайте обидва у dict / hash / масиві: keys[data] = key
    • також counts[data] = 0якщо мова вимагає ініціалізації
  3. Читання всіх файлів даних:
    1. використовуйте регулярне вираження, щоб знайти дані "ТЕКСТ-НОМЕР" на початку кожного рядка,
    2. приріст counts[data]по одному,
    3. і негайно вивести keys[data], рядок і counts[data].

Я написав приклад сценарію як в Perl, так і в Python, тому ваш вибір:

process.pl

#!/usr/bin/env perl
use strict;

sub usage {
    print "Usage: $0 <key_file> <data_file...>\n";
    return 2;
}

my $keys_file = shift(@ARGV) // exit(usage);
my @data_files = @ARGV;

my %keys;   # $data => $primarykey
my %counts; # $data => $count

# Read keys

open(my $fh, "<", $keys_file) or die "$!";
while (my $line = <$fh>) {
    chomp($line);
    my ($key, $datum) = split(/,/, $line, 2);
    if (!defined $datum) {
        warn "$keys_file: line $. not in KEY,DATA format: '$line'\n";
        next;
    }

    $keys{$datum} = $key;
    $counts{$datum} = 0;
}
close($fh);

# Read and output data

my $ex = qr/^(\w+-\d+)\w*/;
for my $data_file (@data_files) {
    open(my $fh, "<", $data_file) or die "$!";
    while (my $line = <$fh>) {
        chomp($line);
        if ($line =~ /$ex/) {
            my $datum = $1;
            if (!defined $keys{$datum}) {
                warn "no primary key found for data '$datum'\n";
                next;
            }

            # Increment count, then print processed line immediately
            $counts{$datum}++;
            print "$keys{$datum},$&,$counts{$datum}\n";
        }
        else {
            warn "$data_file: line $. does not begin with TEXT-NUMBER: '$_'\n";
        }
    }
    close($fh);
}

process.py

#!/usr/bin/env python
from __future__ import print_function
import sys
import re

def usage():
    print("Usage: %s <key_file> <data_file...>" % sys.argv[0])
    return 2

try:
    keys_file = sys.argv[1]
    data_files = sys.argv[2:]
except IndexError:
    sys.exit(usage())
except ValueError:
    sys.exit(usage())

keys = {}
counts = {}

# Read keys

for line in open(keys_file, "r"):
    try:
        key, datum = line.strip().split(",", 1)
    except ValueError:
        print("%s: line not in KEY,DATA format: %r" \
            % (keys_file, line.strip()), file=sys.stderr)
        continue

    keys[datum] = key
    counts[datum] = 0

# Read and output data

ex = re.compile(r'^(\w+-\d+)\w*')
for data_file in data_files:
    for line in open(data_file, "r"):
        line = line.strip()
        m = re.match(ex, line)
        if m:
            datum = m.group(1)
            if datum not in keys:
                print("no primary key found for data %r" % datum,
                    file=sys.stderr)
                continue

            # Increment count, then print processed line immediately
            counts[datum] += 1
            print("%s,%s,%d" % (keys[datum], m.group(0), counts[datum]))
        else:
            print("%s: line does not begin with TEXT-NUMBER: %r" \
                % (data_file, line.strip()), file=sys.stderr)

2

Я би робив це в Python, використовуючи регулярні вирази . Просто введіть pythonсвою оболонку, щоб побачити, чи встановлена ​​вона.

В іншому випадку ви можете використовувати Perl . Просто введіть perlсвою оболонку, щоб побачити, чи встановлена ​​вона. Є вбудована підтримка регулярних виразів .


Чи можете ви навести кілька прикладів того, як ним користуватися?
Oxwivi

@Oxwivi: Ось декілька , але мова не може бути вивчена лише з "деяких прикладів" ... "Навчання Perl" та подібних книг може стати гарним початком.
grawity

@grawity Вибачте за те, що повернувся до вас так пізно, я зіткнувся з несподіваними проблемами, пов’язаними зі створенням даних. Я зробив це так: perl process.pl */images products.csv > images- кілька файлів даних, але немає конфліктів. Однак результати були без ключів - наприклад: ,ABD-47,2. Область, відведена для ключового значення, порожня. Крім того, якщо ви хочете, будь ласка, додайте власну відповідь, оскільки, швидше за все, я оберу вашу.
Oxwivi

@grawity Обробляється лише перший зібраний файл * / зображення. Посилання безпосередньо на цей файл працює як очікувалося.
Oxwivi

@grawity Що саме unmatched inputмає означати? У файлі ключів не знайдено відповідності?
Oxwivi

2

Процес 1

perl count.pl datafile 

де count.pl - щось подібне

#!perl
use strict;
use warnings;

my %headwordcount;

while (<>) {
  if (/^([A-Z]+-\d+)/) { $headwordcount{$1}++; }
  # else { warn "Bad data: $_"; } # uncomment line for data warnings
}

END {
  foreach (sort keys %headwordcount) {
     print "$_,$headwordcount{$_}\n";
  }
}

Неперевірений, застереження емптор.

Процес 2

Додайте щось на кшталт

   my %key;

   BEGIN {
     my $keyfilename = 'primary.key';
     open my $fh, '<', $keyfilename or die "Can't read '$keyfilename' - $!\n";
     while (<$fh>) {
        chomp;
        my ($key,$headword) = split(/,/, $_, 2);
        $key{$headword} = $key;        
     }
     close $fh;
   }

і змінити рядок друку END {}на

   print "$key{$_},$_,$headwordcount{$_}\n";

Знову неперевірений.

Ви будете генерувати попередження, якщо файл даних містить заголовки, які не містяться у файлі ключів. Ви можете перевірити, чи $key{$_}не визначено, і якщо так, надрукуйте без клавіші.


Що повинен робити цей сценарій? Перший процес, який я описав?
Oxwivi

@Oxwivi: Так. Якщо ви не можете легко слідувати коду. Можливо, найкраще спробувати іншу відповідь. Якщо ви розумієте, що баш-сценарії та / або awk, Perl не повинен бути надто складним.
RedGrittyBrick

Я використовував базові сценарії bash, хоча не можу сказати, що я добре їх дотримувався (в основному вбудовані синтаксиси). І чи я додаю нові коди, які ви редагували, у відповідь з відступом?
Oxwivi

@Oxwivi, так, додайте новий матеріал одразу після цього my %headwordcount;(крім printрядка заміни, звичайно, який замінює той, що знаходиться в ÈND … foreachциклі).
RedGrittyBrick

Гаразд, дуже дякую! Одне останнє - datafileце замінити на вхідний файл, що очевидно, але чи ...слід за ним деякі конкретні речі Perl?
Oxwivi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.