【问题标题】:Padding for a file containing Russian Cyrillic characters in a file not working - one Russian character is counted as 2 bytes在文件中填充包含俄语西里尔字符的文件不起作用 - 一个俄语字符计为 2 个字节
【发布时间】:2019-10-23 12:17:38
【问题描述】:

我正在尝试在 Unix 中创建一个具有固定列长度的文件。该文件包含俄语西里尔字符,这些字符的解释与普通的 1 字节字符不同。

我正在使用下面的脚本来修改文件(列的分隔符是@-@,行分隔符是\r\n):

input_file=$1
output_file=$2

awk -F '@-@' '{printf("%-200s%-200s%-200s%-200s%-200s%-200s%-200s%-200s\r\n", $1, $2, $3, $4, $5, $6, $7, $8)}' $input_file > $output_file

对于具有普通字符的列,输出文件包含正确的 200 个字符的列,但对于具有 30 个西里尔字符的列,输出列仅包含 170 个字符。这样,文件中的行将不会具有相同的长度,因为西里尔字符占用 2 个字节,代码将解释字节而不是字符。

示例:НИКОЛАЕВНА 有 10 个字符,但脚本将其计算为有 20 个字符,因为它占用 20 个字节。

一个输入文件示例:

НИКОЛАЕВНА@-@russ@-@12345@-@asklle@-@НИКОЛАЕВНА@-@454@-@111@-@asdfg

您能否建议一种方法来创建填充以使所有行具有相同数量的字符?

谢谢!

【问题讨论】:

    标签: unix cyrillic


    【解决方案1】:

    我不相信 awk 可以做到这一点,但只要你的语言环境没有设置为“C”,gawk 就应该默认处理这个问题。例如,LC_ALL=en_US.UTF-8 应该使用 gawk 提供预期的行为。

    【讨论】:

      【解决方案2】:

      我建议你使用gawk 基于字符的字符串函数substr,来修剪你的字符串。 标准的 gawk printf 宽度格式化函数是基于字符的。检查您是否使用最新的gawk

      要将所有字段修剪为 200 个字符:

      for (i = 1; i <= NF; i++) $i = substr($i,1,200);
      

      所以你的脚本应该是:

      awk -F '@-@' '{for(i=1;i<=NF;i++)$i=substr($i,1,200);printf("%-200s%-200s%-200s%-200s%-200s%-200s%-200s%-200s\r\n", $1, $2, $3, $4, $5, $6, $7, $8)}' $input_file > $output_file
      

      或者更简洁:

      script.awk

      {
          for (i = 1; i <= 8; i++) {
              $i = substr($i,1,200);
              printf("%-200s", $i);
          }
          print;
      }
      

      【讨论】:

      • 感谢您的回复!但是,问题不在于宽度超过 200 个字符,而在于列没有达到最大宽度(在这种情况下为 200),因为俄语字符被解释为 2 个字节,所以这些行的字符将保持较短的长度。所以在这种情况下,我认为没有必要修剪它们,因为它没有任何效果,我需要完全相反 - 使一个俄语字符计为 1 个字节而不是 2 个字节。
      【解决方案3】:

      试试下面的awk 脚本:

      script.awk

      BEGIN {FS="@-@"; # field separator is '@-@'
          h="          "; # length(h) = 10
          h=h h h h h h h h h h; # length(h) = 100
          h=h h; # length(h) = 200
      }
      {
          for (i = 1; i <= 8; i++) {
              #length is character based function
              head = substr(h,1,(length(h)-length($i))); # cut alignment head to the correct length
              printf("%s%s", head, $i); # output the current aligned field
          }
          print;
      }
      

      【讨论】:

        猜你喜欢
        • 2015-10-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多