Запретить SAS автоматически удалять конечные пробелы в строке

У меня есть пример набора данных, как показано ниже.

data d01;
   infile datalines dlm='#';
   input Name & $15. IdNumber & $4. Salary & $5. Site & $3.;
   datalines;
アイ# 2355# 21163# BR1
アイウエオ# 5889# 20976# BR1
カキクケ# 3878# 19571# BR2
;

data _null_ ;
 set d01 ;
 file "/folders/myfolders/test.csv" lrecl=1000 ;
 length filler $3;
 filler = '   ';
 w_out = ksubstr(Name, 1, 5) || IdNumber || Salary || Site || filler;
 put w_out;
run ;

Я хочу экспортировать этот набор данных в csv (формат с фиксированной шириной), и каждая строка будет иметь длину 20 байт (20 1-байтовых символов).

введите здесь описание изображения

Но SAS автоматически удаляет мои конечные пробелы. Таким образом, результат будет 17 байт для каждой строки. (наполнитель обрезан)

Я знаю, что могу вставить наполнитель вот так.

put w_out filler $3.;

Но это не сработает, если столбец «сайт» пуст, SAS обрежет его столбец, и результат также не будет равен 20 байтам для каждой строки.


person EagerToLearn    schedule 15.08.2019    source источник
comment
Этот выходной формат НЕ является файлом CSV. Он не имеет значений, разделенных запятыми. Это даже не файл с разделителями, это файл фиксированного формата. Вероятно, вы НЕ хотите использовать многобайтовый набор символов с файлом фиксированного формата именно по той причине, по которой у вас возникли проблемы.   -  person Tom    schedule 15.08.2019
comment
@ Том Спасибо за ответ. На самом деле расширение файла не имеет отношения к формату файла. Но требование состоит в том, чтобы экспортировать файл формата фиксированной ширины в файл с расширением csv. Я знаю, что многобайтовый набор символов вызывает проблемы, но у меня нет другого выбора, используя SAS 9.4 University Edition, я не могу изменить кодировку сеанса, кроме как придерживаться кодировки UTF-8 по умолчанию.   -  person EagerToLearn    schedule 19.08.2019
comment
Я просто предупреждал вас, что любые программы, которые попытаются прочитать этот файл, будут иметь те же проблемы с чтением файла, что и ваша программа SAS с записью файла. Кроме того, вы используете расширение для своего имени файла, которое вызовет путаницу, поскольку оно означает определенный тип файла, а файл, который вы создаете, НЕ имеет такого формата.   -  person Tom    schedule 19.08.2019
comment
Привет, Том, я понимаю, о чем ты пытаешься предупредить. Во-первых, расширение имени файла не вызовет путаницы, так как оно является требованием нашей работающей системы (> 15 лет). Во-вторых, у нас нет проблем с записью в этом формате с SAS 9.3 (коммерческая версия, которая позволяет нам установить кодировку по умолчанию на то, что нам нравится, но теперь мы больше не можем использовать эту версию, следовательно, 9.4 University Edition) или приложение версии C # .   -  person EagerToLearn    schedule 20.08.2019


Ответы (3)


Я не совсем понял, что вы пытаетесь сделать с ksubstr, но если вы хотите добавить отступы, чтобы получить общую длину до 20 символов, вам, возможно, придется написать дополнительную логику:

data _null_ ;
 set d01 ;
 file "/folders/myfolders/test.csv" lrecl=1000 ;
 length filler $20;
 w_out = ksubstr(Name,1,5) || IdNumber || Salary || Site;

 len = 20 - klength(w_out) - 1;
 put w_out @;
 if len > 0 then do;
   filler = repeat(" ", len);
   put filler $varying20. len;
 end;
 else put;
run ;
person SAS2Python    schedule 15.08.2019
comment
Работал отлично. Большое спасибо. Причина для ksubstr заключается в том, что японский символ в SAS занимает 3 байта, поэтому я не могу использовать стандартную функцию substr, и все это для того, чтобы длина выходной строки составляла 17 символов (байт). - person EagerToLearn; 15.08.2019
comment
Причина использования функций серии K... заключается в том, что они подсчитывают количество символов ВМЕСТО обычных функций, которые просто подсчитывают количество байтов. - person Tom; 15.08.2019
comment
Я понимаю, что делают функции k, но не уверен, почему вы используете здесь subst. - person SAS2Python; 15.08.2019
comment
@PythonRSAS Я хочу убедиться, что выходное значение столбца Name будет состоять из 5 символов (включая пробелы, если они есть). - person EagerToLearn; 17.08.2019
comment
Длина アイウエオ на самом деле составляет 5 байт, но внутри SAS это 15-байтовая строка. - person EagerToLearn; 17.08.2019
comment
В случае, если имя アイ (6 байт), если я не использую ksubstr, выходное значение будет アイ(9 spaces) (15 байт = длина столбца имени) - person EagerToLearn; 17.08.2019
comment
Понял, так что вы, по сути, конвертируете пробелы ascii в «3-байтовые» пробелы. Спасибо за разъяснения - person SAS2Python; 17.08.2019

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

Если вы хотите, чтобы функция PUT записывала определенное количество байтов, просто используйте форматированный оператор PUT. Чтобы количество записываемых байтов менялось в зависимости от значения строки, вы можете использовать формат $VARYING. Синтаксис при использовании $VARYING немного отличается от обычного формата. Вы добавляете вторую ссылку на переменную после спецификации формата, которая содержит фактическое количество байтов для записи.

Вы можете использовать функцию LENGTH(), чтобы вычислить, сколько байтов занимают ваши значения имени. Поскольку он обычно игнорирует завершающий пробел, просто добавьте еще один символ в конец и вычтите один из общей длины.

Чтобы заполнить конец тремя пробелами, вы можете просто добавить три к ширине, используемой в формате для последней переменной.

data d01;
  infile datalines dlm='#';
  length Name $15 IdNumber $4 Salary $5 Site $3 ;
  input Name -- Site;
datalines;
アイ# 2355# 21163# BR1
アイウエオ# 5889# 20976# BR1
カキクケ# 3878# 19571# BR2
Sam#1#2#3
;

filename out temp;
data _null_;
  set d01;
  file out;
  nbytes=length(ksubstr(name,1,5)||'#')-1;
  put name $varying15. nbytes IdNumber $4. Salary $5. Site $6. ;
run;

Полученные результаты:

67    data _null_ ;
68      infile out;
69      input ;
70      list;
71    run;

NOTE: The infile OUT is:
      Filename=...\#LN00059,
      RECFM=V,LRECL=32767,File Size (bytes)=110,
      Last Modified=15Aug2019:09:01:44,
      Create Time=15Aug2019:09:01:44

RULE:     ----+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0
1         アイ   235521163BR1    24
2         アイウエオ588920976BR1    30
3         カキクケ 387819571BR2    28
4         Sam  1   2    3      20
NOTE: 4 records were read from the infile OUT.
      The minimum record length was 20.
      The maximum record length was 30.
person Tom    schedule 15.08.2019

По умолчанию SAS устанавливает параметр NOPAD в операторе FILE, он также устанавливает для каждой строки «переменный формат», что означает, что длина строк может варьироваться в зависимости от записываемых данных. Чтобы явно попросить SAS заполнить ваши записи пробелами, не используйте переменную-заполнитель, просто:

  • Установите LRECL на ширину файла, который вам нужен (20)
  • Установите параметр PAD или установите RECFM=F

Образец кода:

data _null_ ;
 set d01 ;
 file "/folders/myfolders/test.csv" lrecl=20 PAD;
 w_out = Name || IdNumber || Salary || Site;
 put w_out;
run ;

Подробнее здесь: http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a000171874.htm#a000220987

person mjsqu    schedule 15.08.2019
comment
Спасибо за ответ. Но я не могу указать ширину заранее. Поскольку SAS обрабатывает японский символ как 3 байта на символ внутри своего сеанса. Например, アイウエオ будет 15 байт внутри сеанса... - person EagerToLearn; 15.08.2019
comment
Извините, я отредактировал свой вопрос. Вот почему я должен использовать ksubstr(Name, 1, 5) при экспорте данных - person EagerToLearn; 15.08.2019