Модификация формата даты в текстовом файле - PullRequest
2 голосов
/ 21 июля 2009

У меня есть несколько текстовых файлов, содержащих следующие строки:

07JAN01 , -0,247297942769082E + 07, -0,467133797284279E + 07, 0,355810777473149E + 07

07JAN02 , -0,247297942405032E + 07, -0,467133797586388E + 07, 0,355810777517715E + 07

07JAN03 , -0,247297942584851E + 07, -0,467133797727224E + 07, 0,355810777627353E + 07

. , , .

. , , .

Мне нужно создать скрипт, который изменит формат даты на:

01/01/07 , -0,247297942769082E + 07, -0,467133797284279E + 07, 0,355810777473149E + 07

02/01/07 , -0,247297942405032E + 07, -0,467133797586388E + 07, 0,355810777517715E + 07

03/01/07 , -0,247297942584851E + 07, -0,467133797727224E + 07, 0,355810777627353E + 07

. , , .

. , , .

Я искал подходящую команду sed или grep, чтобы извлечь только некоторые символы из каждой строки, чтобы определить ее как переменную в моем скрипте. Поскольку я хотел бы «реорганизовать» дату, я думал об определении трех переменных, где для первой строки это будет:

а = 07

b = JAN (мне нужно реализовать "сценарий" в сценарии, чтобы справиться с этим, я думаю?)

с = 03

Я посмотрел несколько примеров grep и тонны документов, но ничего действительно ясного не появилось ... нашел кое-что о команде -cut, но ... я не слишком уверен, что она здесь уместна.

Другой вопрос, который у меня возник, касается вывода, так как sed не изменяет входные данные, как я могу напрямую изменить файлы? Есть ли способ?

Любая помощь будет принята с благодарностью:)

Ответы [ 3 ]

4 голосов
/ 21 июля 2009

Я не думаю, что сам grep - правильный инструмент для работы. Вам нужно что-то более выразительное, например Perl или awk:

echo '07JAN01, -0.24729E+07, -0.46713E+07, 0.35581E+07
      07JAN02, -0.24729E+07, -0.46713E+07, 0.35581E+07
      07AUG03, -0.24729E+07, -0.46713E+07, 0.35581E+07' | awk -F, '
{
    yy=substr($1,1,2);
    mm=substr($1,3,3);
    mm=(index(":JAN:FEB:MAR:APR:MAY:JUN:JUL:AUG:SEP:OCT:NOV:DEC",mm)+2)/4;
    dd=substr($1,6,2);
    printf "%02d/%02d/%02d,%s,%s,%s\n",dd,mm,yy,$2,$3,$4
}'

, который генерирует:

01/01/07, -0.24729E+07, -0.46713E+07, 0.35581E+07
02/01/07, -0.24729E+07, -0.46713E+07, 0.35581E+07
03/08/07, -0.24729E+07, -0.46713E+07, 0.35581E+07

Очевидно, это просто прокачка некоторых тестовых данных через скрипт awk из командной строки. Вам лучше поместить это в настоящий файл сценария awk и пропустить его через него.

Если datchg.awk содержит:

{
    yy=substr($1,1,2);
    mm=substr($1,3,3);
    mm=(index(":JAN:FEB:MAR:APR:MAY:JUN:JUL:AUG:SEP:OCT:NOV:DEC",mm)+2)/4;
    dd=substr($1,6,2);
    printf "%02d/%02d/%02d,%s,%s,%s\n",dd,mm,yy,$2,$3,$4
}

, то:

echo '07JAN01, -0.24729E+07, -0.46713E+07, 0.35581E+07
      07JAN02, -0.24729E+07, -0.46713E+07, 0.35581E+07
      07AUG03, -0.24729E+07, -0.46713E+07, 0.35581E+07' | awk -F, -fdatechg.awk

также производит:

01/01/07, -0.24729E+07, -0.46713E+07, 0.35581E+07
02/01/07, -0.24729E+07, -0.46713E+07, 0.35581E+07
03/08/07, -0.24729E+07, -0.46713E+07, 0.35581E+07

То, как это работает, заключается в следующем. Каждая строка разбивается на поля (-F, устанавливает разделитель полей на запятую), и мы извлекаем и обрабатываем соответствующие части поля 1 (дата). Под этим я подразумеваю, что год и день меняются местами, и текстовый месяц превращается в числовой месяц путем поиска в нем строки и манипулирования индексом, в котором он был найден, чтобы он находился в диапазоне от 1 до 12.

Это единственный (относительно) хитрый бит, который делается с некоторой базовой математикой: функция index просто находит позицию в строке вашего месяца (где первый символ равен 1). Таким образом, JAN находится в позиции 2, FEB в 6, MAR в 10, ..., DEC в 46 (набор {2, 6, 10, ..., 46}). Они разделены на 4, поэтому в конечном итоге нам нужно разделить на 4, чтобы получить последовательные номера месяцев, но сначала мы добавим 2, чтобы деление работало хорошо. Добавление 2 дает вам набор {4, 8, 12, ..., 48}. Затем вы делите на 4, чтобы получить {1, 2, 3, ... 12} и ваш номер месяца:

Text   Pos   +2   /4
----   ---   --   --
JAN      2    4    1
FEB      6    8    2
MAR     10   12    3
APR     14   16    4
MAY     18   20    5
JUN     22   24    6
JUL     26   28    7
AUG     30   32    8
SEP     34   36    9
OCT     38   40   10
NOV     42   44   11
DEC     46   48   12

Тогда мы просто выводим новую информацию. Очевидно, что это может помешать, если вы предоставите неверные данные, но я предполагаю либо:

  • данные хорошие; или
  • вы добавите свои собственные проверки ошибок.

Что касается непосредственного изменения файлов, то проверенная временем традиция UNIX состоит в том, чтобы использовать сценарий оболочки для сохранения текущего файла в другом месте, обрабатывать его для создания нового файла, а затем перезаписывать старый файл новым файлом (но не касаясь сохраненный файл, на случай, если что-то пойдет не так).

Я не буду больше отвечать на вопрос дольше , подробно описав это, вы, вероятно, уже заснули: -)

3 голосов
/ 21 июля 2009

Немного неуклюже, но вы могли бы сделать:

sed -e 's/^\(..\)JAN\(..\)/\2\/01\/\1/'
sed -e 's/^\(..\)FEB\(..\)/\2\/02\/\1/'
...

Чтобы запустить sed на месте, см. Параметр командной строки -i:

sed -i -e ...

Редактировать

Просто чтобы указать, что это отвечает на предыдущую версию вопроса, где не был указан AWK.

1 голос
/ 21 июля 2009
awk 'BEGIN{
    OFS=FS=","
    # create table of mapping of months to numbers
    s=split("JAN:FEB:MAR:APR:MAY:JUN:JUL:AUG:SEP:OCT:NOV:DEC",d,":")
    for(o=1;o<=s;o++){
        m=sprintf("%02s",o)   # add 0 is single digit    
        date[d[o]]=m
    }
}
{
    yr=substr($1,1,2)
    mth=substr($1,3,3)
    day=substr($1,6,2)
    $1=day"/"date[mth]"/"yr    
}1' file
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...