【问题标题】:Converting months between numeric and number using awk使用 awk 在数字和数字之间转换月份
【发布时间】:2013-01-15 16:22:14
【问题描述】:

在过去的考试论文中,我有一个问题:

月份可以用不同的方式表示,例如数字 (1, 2, ..., 12),或作为三个字母的月份名称(Jan、Feb、...、Dec)。 建议如何使用 awk 中的关联数组从 三个字母的月份名称到月份编号,反之亦然, 将月份数字转换为三个字母的月份名称。

所以我想我会使用格式为月份的输入为 $1 的关联数组:

number_to_month["Jan"] = 1;
print number_to_month[$1]

但对我来说,这似乎并没有很好地利用关联数组的力量,而且我必须在数组中手动​​初始化每个月。

我还有哪些其他选择?

【问题讨论】:

    标签: awk associative-array type-conversion


    【解决方案1】:

    内置的split函数是你的朋友,循环可以将name-from-number版本复制到number-from-name:

    BEGIN {
        split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",month)
        for (i in month) {
            month_nums[month[i]]=i
        }
    }
    END {
        for (i in month) {
            print i "\t" month[i]
        }
        for (m in month_nums) {
            print m "\t" month_nums[m]
        }
    }
    

    BEGIN 块显示了如何执行此操作。然后END 块只是让您验证它。

    我得到的输出(使用 gawk 4.0.1)是:

    4       Apr
    5       May
    6       Jun
    7       Jul
    8       Aug
    9       Sep
    10      Oct
    11      Nov
    12      Dec
    1       Jan
    2       Feb
    3       Mar
    Feb     2
    Sep     9
    Jan     1
    May     5
    Apr     4
    Oct     10
    Dec     12
    Nov     11
    Jul     7
    Mar     3
    Aug     8
    Jun     6
    

    请注意通常的尴尬(嘿!AWKwardness)由于无法强制数组for 循环的访问顺序。

    【讨论】:

    • split() 的返回代码告诉您有多少个月,因此将其分配给一个变量并从 1 循环到该值,而不是使用“in”运算符。
    【解决方案2】:

    如果您不想手动初始化数组,一种选择是:

    echo | awk '{x=mktime("2013 01 01 0 0 0"); for(i=0;i<12;i++){s=strftime("%b",x+((31*i)*86400)); m[s]=i+1;n[i+1]=s;}}'
    

    这将创建 2 个数组 m 和 n,其中 m 是数组,其中 index 是月份名称,value 是月份编号,n 数组反之亦然。

    【讨论】:

    • 可爱。需要gawk,但您可以获得本地化支持。
    【解决方案3】:
    $ cat tst.awk
    BEGIN {
       mths="JanFebMarAprMayJunJulAugSepOctNovDec"
    
       name="Mar"; print name " -> " (match(mths,name)+2)/3
       name="Sep"; print name " -> " (match(mths,name)+2)/3
    
       nbr=3;      print nbr  " -> " substr(mths,(nbr*3)-2,3)
       nbr=9;      print nbr  " -> " substr(mths,(nbr*3)-2,3)
    }
    
    $ awk -f tst.awk
    Mar -> 3
    Sep -> 9
    3 -> Mar
    9 -> Sep
    

    这是修改后的@dmckee 脚本以产生有序输出:

    $ cat tst2.awk
    BEGIN {
        n = split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",month)
        for (i in month) {
            month_nums[month[i]]=i
        }
    
        for (i=1; i<=n; i++) {
            print i "\t" month[i]
        }
        for (i=1; i<=n; i++) {
            m = month[i]
            print m "\t" month_nums[m]
        }
    }
    $ awk -f tst2.awk
    1       Jan
    2       Feb
    3       Mar
    4       Apr
    5       May
    6       Jun
    7       Jul
    8       Aug
    9       Sep
    10      Oct
    11      Nov
    12      Dec
    Jan     1
    Feb     2
    Mar     3
    Apr     4
    May     5
    Jun     6
    Jul     7
    Aug     8
    Sep     9
    Oct     10
    Nov     11
    Dec     12
    

    【讨论】:

      【解决方案4】:

      当他们提到 awk 时,我认为这些月份的详细信息和整数映射都保存在数据文件中,例如

      1 JAN JANUARY jan
      2 FEB FEBRUARY feb
      ...
      

      等等

      你可以使用 awk

      awk '/JAN/ {print $1}' temp.txt
      

      【讨论】:

      • 这是个好主意(提供了很大的灵活性并使用了许多不同的表示形式),但是您应该展示如何在处理 不同的 文件时访问结果。也许将getline &lt;datefile.txt 包装在一个匹配一列并返回不同列的函数中。或匹配 any 列并返回特定的列。
      • 不要将 getline 包装在匹配一列并返回另一列的函数中。要从文件中读取数据,请在与 NR==FNR 条件关联的操作块中填充文件中的数组,或者在 getline 循环中仔细编写的 BEGIN 中执行。
      【解决方案5】:

      这是另一个例子,使用了几个辅助函数:

      awk '
          BEGIN { 
              j = 0
              for (i=1; i<=34; i+=3) {
                  months[substr("JanFebMarAprMayJunJulAugSepOctNovDec",i,3)] = ++j
              }
          }
          function month2num(month) {
              return (month in months ? months[month] : -1)
          }
          function num2month(n) {
              for (month in months) {
                  if (months[month] == n)
                      return month
              }
              return ""
          }
          BEGIN {
              print "Jan: " month2num("Jan")
              print "Dec: " month2num("Dec")
              print "Foo: " month2num("Foo")
              print "3: " num2month(3)
              print "12: " num2month(12)
              print "14: " num2month(14)
          }
      '
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-30
        • 2018-06-11
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多