awk — проверка таймкода

В моем файле каждая строка выглядит примерно так:

\18:49:25 1920/11/29\ 0.25

Есть ли способ, как я могу проверить правильность тайм-кода, чтобы в нем не было опечаток (например, максимум 12 месяцев, год, написанный 4 числами и т. д.), когда я сохранил это в переменной?

\%H:%M:%S %Y/%m/%d\

Спасибо

P.S. Я знаю, что проверка не может работать каждый раз (я не могу отличить минуты от секунд, но я могу проверить, что у меня нет 13 месяцев и т. д.)

РЕДАКТИРОВАТЬ: тайм-код не фиксирован. Файл данных может выглядеть так:

    *1920.11.29 18.49.25* 0.25

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

*%Y.%m.%d %H.%M.%S*

EDIT2: Похоже, я не совсем ясно выразился, поэтому вот несколько примеров того, чего я хочу достичь:

1)

$ cat input.txt
29/11/1920 17:50
30/11/1920 18:20
01/12/1920 07:20
...

$ ./checktimecode "%d/%m/%Y %H:%M" input.txt

Результат= таймкод ОК

2)

$ cat input.txt
**1920/11@17:50**
**1920/12@18:20**
**1920/13@07:20**
...

$ ./checktimecode "**%Y/%d@%H:%M**" input.txt

Результат= таймкод ОК

$ ./checktimecode "**%Y/%m@%H:%M**" input.txt

Результат = ПЛОХОЙ таймкод

3)

$ cat input.txt
!17/50/20\29/11/1920&
!18/20/50\30/11/1920&
!07/18/05\01/12/1920&
...

$ ./checktimecode "!%H/%M/%S\%d/%m/%Y&" input.txt

Результат= таймкод ОК

$ ./checktimecode "%H/%M/%S\%d/%m/%Y&" input.txt

Результат = ПЛОХОЙ таймкод


person user1290065    schedule 06.04.2012    source источник
comment
Странно, что вы думаете, что не можете различить минуты и секунды, но вы уверены, что не перепутаете месяцы и дни, учитывая, что существуют различные соглашения о порядке записи полей даты, но время довольно единообразно: часы, минуты и секунды.   -  person Kaz    schedule 07.04.2012
comment
Возможный дубликат stackoverflow.com/questions/10085538/, но желаемых ответов нет. Похоже, что использование внешнего языка, такого как c/python, является лучшим способом приблизиться к этому. вива СКЖ   -  person tsusanka    schedule 12.04.2012


Ответы (4)


Дата образца:

$ cat input.txt

\18:00:00 1920/11/29\ OK
\18:00:00 1920/13/29\ KO
\00:61:00 1920/02/29\ KO
\25:00:00 1920/11/29\ KO
\00:00:00 1920/11/29\ OK

awk скрипт

#!/usr/bin/awk -f

BEGIN{
    FS = "\\"
}

!check_date_time($2)

function check_date_time(dt,     a,date,time,year,mon,day,hour,min,sec)
{
    split(dt, a, " ")
    date = a[2]
    time = a[1]

    split(date, a, "/")
    year = a[1]
    mon  = a[2]
    day  = a[3]

    split(time, a, ":")
    hour = a[1]
    min  = a[2]
    sec  = a[3]

    return check_date(year, mon, day) && check_time(hour, min, sec)
}

function check_time(hour, min, sec)
{
    return 0<=hour && hour<=23 && 0<=min && min<=59 && 0<=sec && sec<=59
}

function check_date(year, mon, day)
{
    if (mon < 0 || mon >= 13)
        return 0
    else if (day == 31 && (mon == 4 ||  mon == 6 || mon == 9 || mon == 11))
        return 0;
    else if (day >= 30 && mon == 2)
        return 0;
    else if (mon == 2 && day == 29 && ! (  year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)))
        return 0;
    else
        return 1;
}

выход

$ awk -f chk_date_time.awk input.txt

\18:00:00 1920/13/29\ KO
\00:61:00 1920/02/29\ KO
\25:00:00 1920/11/29\ KO
person kev    schedule 07.04.2012
comment
Извините, я, по-видимому, не ясно выразил, чего хочу достичь, я обновил вопрос примерами. Я не ограничиваюсь только двумя форматами файла, есть практически бесконечные комбинации таймкодов. - person user1290065; 08.04.2012
comment
@user1290065. Вам нужно разделить задачу на два этапа: (1) преобразовать строку даты в унифицированный формат. (2) сделать все остальное. - person kev; 08.04.2012

Используйте файл Python time.strptime() или datetime.strptime():

#!/usr/bin/python2.6
from datetime import datetime
import sys
format = sys.argv[1]
file = sys.argv[2]

with open(file, 'r') as f:
    for line in f:
        try:
            datetime.strptime(line.rstrip(), format)
        except:
            print "BAD timecode"
            sys.exit(1)

print "timecode OK"

Изменить:

Применение:

$ ./checktimecode "%d/%m/%Y %H:%M" input.txt
person Dennis Williamson    schedule 08.04.2012
comment
Это выглядит очень просто, спасибо за решение с Python. Но если возможно, я бы очень хотел иметь решение с использованием bash - person user1290065; 10.04.2012
comment
@ user1290065: AWK — это язык программирования, как и Python. Когда вы говорите, что вам нужно решение на Bash, вы имеете в виду язык оболочки? Потому что AWK — это не больше Bash, чем Python. Кстати, Perl также имеет функцию strptime. Кроме того, библиотека time в Linux имеет strptime, так что вы можете легко написать это на C В конце концов, зачем изобретать велосипед? - person Dennis Williamson; 10.04.2012
comment
Обратите внимание, что некоторые версии date, например для OS X использует strptime для принятия строк формата для анализа ввода. Возможно, это можно использовать в сценарии оболочки, чтобы делать то, что вы хотите, но это будет менее переносимо. - person Dennis Williamson; 10.04.2012
comment
Извините, я имел в виду в оболочке. А зачем изобретать велосипед? Потому что это часть моего задания, которое я должен написать, используя только стандартные функции оболочки, и это последняя часть сценария, которую я не могу понять. - person user1290065; 10.04.2012
comment
@ user1290065: Другие ответы содержат некоторые подсказки, но вам придется добавить дополнительный код для обработки общего случая разбора и обработки кодов произвольного формата. Посмотрите на исходник для strptime, чтобы увидеть сложность, которую вам нужно будет реализовать повторно. К сожалению, если доступна командная строка strptime, это не является распространенным явлением. - person Dennis Williamson; 10.04.2012

Вы можете проверить H, M, S, Y, m и d по любым правилам, которые хотите...

awk -F'[\\\\:/ ]' '{H=$2; M=$3; S=$4; Y=$5; m=$6; d=$7; print "=" H "=" M "=" S "=" Y "=" m "=" d "="}'
person amit_g    schedule 06.04.2012
comment
Но я не знаю, как выглядит таймкод, он может выглядеть совсем по-другому. Но как бы это ни выглядело, я буду хранить его с % вместо чисел в какой-то переменной. Или я не правильно понял ваш пример. - person user1290065; 07.04.2012
comment
Я не уверен, понимаю ли я. Вы хотите сказать, что даже формат не фиксирован? - person amit_g; 07.04.2012
comment
Файл также может выглядеть так, например: \1920/11/29 18:49:25\ 0.25 Но я этого не знаю. Единственное, что я знаю, это то, что в этом случае у меня будет в моей переменной это: \%Y/%m/%d %H:%M:%S\ И теперь я хочу проверить, если файл данных имеет правильный формат и в нем нет опечаток, экв. макс 12 месяцев, год пишется 4 цифрами и т.д.. Стало понятнее? - person user1290065; 07.04.2012
comment
Итак, как вы ожидаете, что программа поймет это? Как бы вы сделали это вручную? Вы должны определить некоторую логику для работы программы. - person amit_g; 07.04.2012
comment
Пожалуйста, взгляните на вопрос, я добавил несколько примеров. Надеюсь теперь понятно. - person user1290065; 08.04.2012

TXR:

@(do (defvar counter (range 1)))
@(collect :vars ())
@  (bind lineno @(pop counter))
@;;; 
@;;; Here we can add numerous cases for different date formats.
@;;;
@  (try)
@    (cases)
\@hh:@mm:@ss @year/@mo/@da\ @stuff
@    (or)
*@year.@mo.@da @hh.@mm.@ss* @stuff
@    (or)
@line
@    (throw error `line @lineno: unrecognized format`)
@    (end)
@    (filter :tonumber hh mm ss year mo da)
@    (do
       (each ((n (list hh mm ss year mo da)))
         (if (null n)
           (throw 'error `line @lineno: bad number`))
         (if (< n 0)
           (throw 'error `line @lineno: negative number`)))
       (if (> hh 23)
         (throw 'error `line @lineno: hour > 23`))
       (if (> mo 12)
         (throw 'error `line @lineno: month > 13`)))
@  (catch error (err))
@    (do (format t "~a\n" err))
@  (end)
@(end)

Данные:

\28:49:25 1920/11/29\ 0.25
*1920.13.29 18.49.25* 0.25
asdf *1920.28
*-1920.11.29 18.49.25* 0.25
*1920.x3.29 18.49.25* 0.25

Бегать:

$ txr times.txr  times.txt  | sed -e 's/^/    /'
line 1: hour > 23
line 2: month > 13
line 3: unrecognized format
line 4: negative number
line 5: bad number

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

person Kaz    schedule 07.04.2012