Замените строку пользовательскими значениями и выполните итерацию для всех случаев - PullRequest
0 голосов
/ 10 ноября 2018

Я пытаюсь заменить текст в файле, используя SED, PERL, AWK или скрипт на python. Я попробовал пару вещей, но, похоже, ничего не получилось.

У меня есть следующее в текстовом файле с именем data.txt

&st=ALPHA&type=rec&uniId=JIM&acceptCode=123&drainNel=supp&
&st=ALPHA&type=rec&uniId=JIM&acceptCode=167&drainNel=supp&
&st=ALPHA&type=rec&uniId=SARA&acceptCode=231&drainNel=ured&
&st=ALPHA&type=rec&uniId=SARA&acceptCode=344&drainNel=iris&
&st=ALPHA&type=rec&uniId=SARA&acceptCode=349&drainNel=iris&
&st=ALPHA&type=rec&uniId=DAVE&acceptCode=201&drainNel=teef&

1) Скрипт будет принимать входной аргумент в виде числа, например: 10000

2) Я хочу заменить весь текст ALPHA на заданное длинное число в качестве аргумента и увеличить его на 100, например. если uniId то же самое. Если он отличается, он увеличивается на 5000, например,

3) Я хочу заменить все acceptCode на первый st для всех строк с одинаковым uniId

. / Script 10000

.. все еще в замешательстве? Ну, конечный результат может быть таким:

&st=10000&type=rec&uniId=JIM&acceptCode=10000&drainNel=supp&
&st=10100&type=rec&uniId=JIM&acceptCode=10000&drainNel=supp&
&st=15100&type=rec&uniId=SARA&acceptCode=15100&drainNel=ured&
&st=15200&type=rec&uniId=SARA&acceptCode=15100&drainNel=iris&
&st=15300&type=rec&uniId=SARA&acceptCode=15100&drainNel=iris&
&st=20300&type=rec&uniId=DAVE&acceptCode=20300&drainNel=teef&

Этот ^ должен быть ЗАМЕНЕН и применен к файлу data.txt - а не просто печатать на экране.

Ответы [ 3 ]

0 голосов
/ 10 ноября 2018

Несколько предположений

Ваше требование 2) Я хочу заменить весь текст ALPHA на заданное длинное число в виде аргумента arg и увеличить его на 100, например. если uniId такой же. Если он отличается, он будет увеличиваться на 5000, например, в сочетании с вашим примером вывода требует, чтобы ваши входные данные были отсортированы в поле uniId . Если файл не отсортирован, приращения 100 и 5000 не приведут к желаемым начальным значениям для каждого uniId

Схема приращения предполагает, что ни у одного значения uniId не будет достаточно записей для увеличения в следующий диапазон 5000, установленный для вновь идентифицированных значений uniId.

#!/usr/bin/env python3

from collections import OrderedDict
import csv
import sys

class TrackingVars(object):
    """
    The TrackingVars class manages the business logic for maintaining the
    st field counters and the acctCode values for each uniId
    """

    def __init__(self, long_number):
        self.uniId_table = {}
        self.running_counter = long_number

    def __initial_value__(self):
        """
        The first encounter for a uniId will have st = acctCode
        """
        retval = (self.running_counter, self.running_counter)
        return retval

    def get_uniId(self, id):
        """
        A convenience method for returning uniId tracking values
        """
        curval, original_value = self.uniId_table.get(id, self.__initial_value__())
        return (curval, original_value)

    def track(self, uniId):
        """
        curval = original_value when a new uniId is encountered.
        If the uniId is known, simply increment curval by 100
        if the uniId is new and there is at least 1 key in the
        tracking table increment curval by 5000
        always update tracking variables
        """
        curval, original_value = self.get_uniId(uniId)
        if uniId in self.uniId_table.keys():
            curval = curval + 100
        else:
            if self.uniId_table:
                curval = curval + 5000
                original_value = curval
        self.running_counter = curval
        retval = (curval, original_value)
        self.uniId_table[uniId] = retval
        return retval


def data_lines(filename):
    """
    Read file as input delimited by &
    """
    with open(filename, "r", newline=None) as fin:
        csvin = csv.reader(fin, delimiter="&")
        for row in csvin:
            yield row

def transform_data_line(line):
    """
    Transform data into key, values pairs
    leading and traling & have no valid key, value pairs
    """
    head = ("head", None)
    tail = ("tail", None)
    items = [head]
    for field in line[1:-1]:
        key, value = field.split("=")
        items.append([key, value])
    retval = OrderedDict(items)
    retval["tail"] = tail
    return retval

def process_data_line(record, text_to_replace, tracking_vars):
    """
    if st value is ALPHA update record with tracking variables
    """
    st = record.get("st")
    if st is not None:
        if st == text_to_replace:
            uniId = record.get("uniId")
            curval, original_value = tracking_vars.track(uniId)
            record["st"] = curval
            record["acceptCode"] = original_value
    return record


def process_file():
    """
    Get the long number from the command line input.
    Initialize the tracking variables.
    Process each row of the file.
    """
    long_number = sys.argv[1]
    tracking_vars = TrackingVars(int(long_number))
    for row in data_lines("data.txt"):
        record = transform_data_line(row)
        retval = process_data_line(record, "ALPHA", tracking_vars)
        yield retval


def write(iter_in, filename_out):
    """
    Write each row from the iterator to the csv.
    make sure the first and last fields are empty.
    """
    with open(filename_out, "w", newline=None) as fout:
        csvout = csv.writer(fout, delimiter="&")
        for row in iter_in:
            encoded_row = ["{0}={1}".format(k, v) for k, v in row.items()]
            encoded_row[0]=""
            encoded_row[-1]=""
            csvout.writerow(encoded_row)

if __name__ == "__main__":
    write(process_file(), "data.new.txt")

выход

$cat data.net.txt

&st=10000&type=rec&uniId=JIM&acceptCode=10000&drainNel=supp&
&st=10100&type=rec&uniId=JIM&acceptCode=10000&drainNel=supp&
&st=15100&type=rec&uniId=SARA&acceptCode=15100&drainNel=ured&
&st=15200&type=rec&uniId=SARA&acceptCode=15100&drainNel=iris&
&st=15300&type=rec&uniId=SARA&acceptCode=15100&drainNel=iris&
&st=20300&type=rec&uniId=DAVE&acceptCode=20300&drainNel=teef&

Заключение

Только вы знаете, почему бизнес-правила для схемы с возрастающим числом таковы. Однако наличие прерывания управления uniId и значения st, зависящего от предыдущего приращения uniId, мне кажется проблематичным. Вы можете обработать несортированные файлы, если каждый новый найденный uniId будет начинаться с новой границы 5000. Например, 15000, 2000, 25000 и т. Д.

P.S

Мне нравятся ответы на AWK и Perl. Они просты и понятны. Они отвечают на вопрос именно так, как он был задан. Теперь все, что нам нужно, это пример SED:)

0 голосов
/ 07 апреля 2019

чуть более эффективное управление, в одну строку gnu awk:

awk  -F\& -vi=10000 -vOFS=\& '{if(NR==1) { ac=i; u=$4; } else { if($4==u) i+=100; else { i+=5000; ac=i; u=$4; } }; $2="st=" i; $5 =gensub(/[0-9]+/,ac,1,$5); print } ' data.txt

Примите любую различную строку в 5-м поле. Спасибо Шон.

0 голосов
/ 10 ноября 2018

Хорошо, вот один из способов, используя awk (для удобства обернутый в скрипт оболочки, потому что это слишком много для однострочного):

#!/bin/sh
# Usage:
# $./transform.sh [STARTCOUNT] < data.txt > temp.txt
# $ mv -f temp.txt data.txt
awk  -F '&' -v "cnt=${1:-10000}" -v 'OFS=&' \
   'NR == 1 { ac = cnt; uni = $4; }
    NR > 1 && $4 == uni { cnt += 100 }
    $4 != uni { cnt += 5000; ac = cnt; uni = $4 }
    { $2 = "st=" cnt; $5 = "acceptCode=" ac; print }'

Выполнение этого в файле, содержащем ваш пример ввода:

$ ./transform.sh 10000 < data.txt
&st=10000&type=rec&uniId=JIM&acceptCode=10000&drainNel=supp&
&st=10100&type=rec&uniId=JIM&acceptCode=10000&drainNel=supp&
&st=15100&type=rec&uniId=SARA&acceptCode=15100&drainNel=ured&
&st=15200&type=rec&uniId=SARA&acceptCode=15100&drainNel=iris&
&st=15300&type=rec&uniId=SARA&acceptCode=15100&drainNel=iris&
&st=20300&type=rec&uniId=DAVE&acceptCode=20300&drainNel=teef&

И версия Perl, которая выполняет редактирование входного файла на месте:

#!/usr/bin/perl -ani -F'&'
# Usage:
# $ ./transform.pl COUNT datafile
use warnings;
use strict;
use English;

our ($count, $a, $uni);

BEGIN {
  $count = shift @ARGV;
  die "Missing count argument" unless defined $count and $count =~ /^\d+$/;
  $ac = $count;
  $uni = "";
  $OFS = '&';
}

if ($NR == 1) {
  $uni = $F[3];
} elsif ($uni ne $F[3]) {
  $count += 5000;
  $ac = $count;
  $uni = $F[3];
} else {
  $count += 100;
}
$F[1] = "st=$count";
$F[4] = "acceptCode=$ac";
print @F;

Запуск его на входе примера:

$ ./transform.pl 10000 data.txt
$ cat data.txt
&st=10000&type=rec&uniId=JIM&acceptCode=10000&drainNel=supp&
&st=10100&type=rec&uniId=JIM&acceptCode=10000&drainNel=supp&
&st=15100&type=rec&uniId=SARA&acceptCode=15100&drainNel=ured&
&st=15200&type=rec&uniId=SARA&acceptCode=15100&drainNel=iris&
&st=15300&type=rec&uniId=SARA&acceptCode=15100&drainNel=iris&
&st=20300&type=rec&uniId=DAVE&acceptCode=20300&drainNel=teef&
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...