需要有关日期表达式的帮助 - csv 文件中的 AWK

需要有关日期表达式的帮助 - csv 文件中的 AWK

情况:csv 文件具有不同日期格式的日期列,我想将它们转换为明确的日期格式(如 +"%m-%d-%Y")。

文件数据示例:文件名 = Date_Test_new.csv

3/29/2019, Test, "I am new to, Unix", 04-05-2023
03/29/19, Test, "I am new to, Unix", 04-5-2023
Apr-29-2019, Test, "I am new to, Unix", "Apr-01-2019"
3/29/2019, Test, "I am new to, Unix", "Apr-01-2019"


**Source Date formats**
DD-MMM-YY -> 08-Sep-23

DD-MMM-YYYY -> 08-Sep-2023

MM/DD/YY -> 09/08/23

MM/DD/YYYY -> 09/08/2023

MM-DD-YYYY -> 09-08-2023

YYYYMMDD -> 20230908

DDMMMYY -> 08Sep23

所需输出

03-29-2019,Test, "I am new to, Unix", 04-05-2023
03-29-2019, Test, "I am new to, Unix", 04-05-2023
04-29-2019, Test, "I am new to, Unix", 04-01-2019
03-29-2019, Test, "I am new to, Unix", 04-01-2019

我尝试过但抛出语法错误:

awk -F ',' '$1="date -d "$1" +"%m-%d-%Y" " ' Date_Test_new.csv > New_Output.csv

简而言之,如何将文件中一整列的日期格式转换为不同的日期格式?

任何帮助对我来说都是一个很好的学习。谢谢

答案1

假设您的真实数据采用有效的 CSV 格式,即字段分隔逗号后没有空格,然后使用 GNU awk for FPATgensub()和 3rg arg 来match()

$ cat tst.awk
BEGIN {
    split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",tmp)
    for (i in tmp) {
        mths[tmp[i]] = i
    }
    FPAT = "[^,]*|(\"([^\"]|\"\")*\")"
    OFS = ","
}
{
    for ( i=1; i<=NF; i++ ) {
        val = gensub(/^"|"$/,"","g",$i)

        day = mth = yr = 0
        if ( match(val,/^([0-9]{1,2})-([[:alpha:]]{3})-([0-9]{2}|[0-9]{4})$/,d) ) {
            # D-MMM-YY or DD-MMM-YY or ...YYYY
            day = d[1]
            mth = mths[d[2]]
            yr  = d[3]
        }
        else if ( match(val,/^([[:alpha:]]{3})-([0-9]{1,2})-([0-9]{2}|[0-9]{4})$/,d) ) {
            # MMM-D-YY or MMM-DD-YY or ...YYYY
            day = d[2]
            mth = mths[d[1]]
            yr  = d[3]
        }
        else if ( match(val,/^([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{2}|[0-9]{4})$/,d) ) {
            # M/D/YY or M/DD/YY or MM/D/YY or MM/DD/YY or ...YYYY
            day = d[2]
            mth = d[1]
            yr  = d[3]
        }
        else if ( match(val,/^([0-9]{1,2})-([0-9]{1,2})-([0-9]{2}|[0-9]{4})$/,d) ) {
            # M-D-YY or M-DD-YY or MM-D-YY or MM-DD-YY or ...YYYY
            day = d[2]
            mth = d[1]
            yr  = d[3]
        }
        else if ( match(val,/^([0-9]{2})([[:alpha:]]{3})([0-9]{2})$/,d) ) {
            # DDMMMYY
            day = d[1]
            mth = mths[d[2]]
            yr  = d[1]
        }
        else if ( match(val,/^([0-9]{4})([0-9]{2})([0-9]{2})$/,d) ) {
            # YYYYMMDD
            day = d[3]
            mth = d[2]
            yr  = d[1]
        }

        if ( length(yr) == 2 ) {
            yr = "20" yr
        }

        day += 0
        mth += 0
        yr  += 0

        if ( (1 <= day) && (day <= 31) &&
             (1 <= mth) && (mth <= 12) &&
             (1 <=  yr) && (yr  <= 9999) ) {
            $i = sprintf("%04d-%02d-%02d", yr, mth, day)
        }
    }
    print
}

$ awk -f tst.awk Date_Test_new.csv
2019-03-29,Test,"I am new to, Unix",2023-04-05
2019-03-29,Test,"I am new to, Unix",2023-04-05
2019-04-29,Test,"I am new to, Unix",2019-04-01
2019-03-29,Test,"I am new to, Unix",2019-04-01

我想我涵盖了您列出的每个日期格式以及更多内容,但只需为else if ( match(...) ) { ... }您希望能够解析的任何其他格式添加块即可。

您还可以match()通过放宽一些正则表达式来合并一些更相似的调用,或者使一些正则表达式更加严格(如果这对您来说更有效)。

更改sprintf()为您喜欢的任何输出格式,但我建议您坚持使用ISO 8601 日期格式, YYYY-MM-DD, 我使用它是为了便于随后处理这些日期。

如果您愿意,可以随意添加或更改有效日期的任何检查。由于我们使用的是 GNU awk,如果您愿意,您可以记住每个块中的输入格式,然后在底部使用mktime()将新创建的日期转换为自纪元以来的秒数,然后strftime()将这些秒转换回原始格式,看看它是否与原始日期相同,以便万无一失地验证您是否准确匹配和转换。留下作为练习......:-)。

如果您的数据在字段分隔后确实有空格,

$ cat file
3/29/2019, Test, "I am new to, Unix", 04-05-2023
03/29/19, Test, "I am new to, Unix", 04-5-2023
Apr-29-2019, Test, "I am new to, Unix", "Apr-01-2019"
3/29/2019, Test, "I am new to, Unix", "Apr-01-2019"

您可以使用以下命令将其转换为有效的 CSV:

$ awk 'BEGIN{FS=OFS="\""} {for (i=1; i<=NF; i+=2) gsub(/, /,",",$i)} 1' file
3/29/2019,Test,"I am new to, Unix",04-05-2023
03/29/19,Test,"I am new to, Unix",04-5-2023
Apr-29-2019,Test,"I am new to, Unix","Apr-01-2019"
3/29/2019,Test,"I am new to, Unix","Apr-01-2019"

上述所有内容都假设您的字段不能包含换行符。如果字段包含换行符,则需要更多工作。有关使用 awk 处理 CSV 的更多信息,请参阅使用 awk 高效解析 csv 的最稳健方法是什么

相关内容