UE4, C , fscanf, сопоставление строк со спецификаторами

#c #parsing #scanf #unreal-engine4 #protein-database

Вопрос:

Я новичок в Unreal Engine, родом из Unity, а также новичок в C . Я пытаюсь импортировать файлы PDB непосредственно в движок с помощью fscanf.

Раздел файла PDB, который я пытаюсь захватить, показан ниже:

 ATOM     15  H1 ATHR A   1       3.035 -14.005  16.173  0.75  6.58           H  
ATOM     16  H1 BTHR A   1       2.914 -14.713  18.488  0.25 11.77           H  
ATOM     17  H2 ATHR A   1       2.830 -14.148  17.523  0.75  6.58           H  
ATOM     18  H2 BTHR A   1       4.980 -14.983  15.512  0.25 11.77           H  
ATOM     19  H3 ATHR A   1       3.680 -15.162  17.238  0.75  6.58           H  
ATOM     20  H3 BTHR A   1       9.013  -8.192  18.474  0.25 11.77           H  
ATOM     21  HA ATHR A   1       3.181 -11.806  16.823  0.75  4.19           H  
ATOM     22  HA BTHR A   1       3.605 -12.290  17.060  0.25  5.98           H  
ATOM     23  HB ATHR A   1       5.699 -13.731  17.989  0.75  4.53           H  
ATOM     24  HB BTHR A   1       4.523 -12.115  19.103  0.25  9.37           H  
ATOM     25  HG1ATHR A   1       3.314 -12.887  19.057  0.75  8.30           H  
ATOM     26  HG1BTHR A   1       4.049 -10.109  18.478  0.25 15.91           H  
ATOM     27 HG21ATHR A   1       6.468 -11.628  19.047  0.75  7.89           H  
 

Я нашел несколько других примеров в библиотеках, использующих спецификаторы, такие как:

const char atom_line_iformat_[] = "ATOM ]%*1cL

Однако при попытке использовать вышеуказанные спецификаторы unreal engine будет выходить из строя каждый раз, если присутствует спецификатор «ATOM».

Мое текущее решение позволяет извлекать данные 3D-координат, но также анализирует другие строки из файла pdb, которые являются нежелательными. Также кажется, что в выходных данных есть повторяющиеся строки, как показано на рисунке ниже.

[дубликаты выходных журналов1

Вы также можете увидеть здесь более неправильные выходные данные, первое изображение-это вывод журнала, второе-данные из файлов pdb, которые неправильно считываются, поскольку это не запись ATOM.

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

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

Я считаю, что мне нужен спецификатор, который проверяет, что первая строка — «АТОМ», но я не смог найти рабочее решение.

Любой совет был бы очень признателен!

Код, найденный ниже:

 FString directory = FPaths::ProjectContentDir();
IPlatformFileamp; file = FPlatformFileManager::Get().GetPlatformFile();

if (file.CreateDirectory(*directory)) {
    FString myFile = directory   "/"   fileName   ".pdb";
    const char* fileLocation = TCHAR_TO_ANSI(*myFile);
    FILE* ptr = fopen(fileLocation, "r");
    if (ptr == NULL) {
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("FILE NOT FOUND."));
        return atomPositions;
    }
    else {
        double xValue = 0;
        double yValue = 0;
        double zValue = 0;
        UE_LOG(LogTemp, Warning, TEXT("RUNNING"));
        while (fscanf(ptr, "%*s %*d %*s %*s %*s %*d %lf %lf %lf %*lf %*lf %*sn", amp;xValue, 
        amp;yValue, amp;zValue) != EOF) 
        {
            UE_LOG(LogTemp, Warning, TEXT("X: %lf, Y: %lf, Z: %lf"), xValue, yValue, zValue);
        }
    }
}
 

Комментарии:

1. Зачем сравнивать agianst EOF , а не 3 в while (fscanf(ptr, "%*s %*d %*s %*s %*s %*d %lf %lf %lf %*lf %*lf %*sn", amp;xValue, amp;yValue, amp;zValue) != EOF)

2. Я предположил, что это позволяет fscanf выполнять цикл до EOF, я добавил его в оператор while, увидев, что он используется в другом операторе онлайн.

3. Mortamass 1) Поскольку цикл имеет смысл продолжать только в том случае, если прочитаны 3 успешных FP, а не 2, 1, 0 или EOF , лучше использовать while (fscanf(ptr, ...) == 3) 2) Кодирование путем имитации наследует хорошие и плохие привычки.

Ответ №1:

Код помечен C и scanf— странное сочетание.

Я продолжу с fgets() sscanf() объяснением, но использование getline() и другой синтаксический анализ кода больше похожи на C .


*scanf() и друзья ужасно восстанавливаются после ввода, который не соответствует ожидаемому формату.

Поскольку ввод-это ориентация строки, лучше всего прочитать строку, а затем проанализировать ее.

 char buffer[200];
while (fgets(buffer, sizeof buffer, ptr)) {
  if (sscanf(buffer, "%*s %*d %*s %*s %*s %*d %lf %lf %lf %*lf %*lf %*sn", 
      amp;xValue, amp;yValue, amp;zValue) != 3) {
    fprintf(stderr, "Unable to parse <%s>n", buffer);
    exit(-1):
  }
  UE_LOG(LogTemp, Warning, TEXT("X: %lf, Y: %lf, Z: %lf"), xValue, yValue, zValue);
}
 

Я уверен, что при быстром выходе кода из не проанализированной строки OP локализует проблему сканирования.

 // Hint - format and input are mismatched
%*d %*s %*s %*s %*d
27 HG21ATHR A   1
 

Комментарии:

1. Все пробелы (и n) в строке формата являются ненужными и должны быть удалены. Конечные %* совпадения также бессмысленны и должны быть удалены.

2. На самом деле, учитывая формат фиксированной ширины, было бы лучше if (sscanf(buffer OFFSET, "%f%f%f", … где OFFSET (фиксированное) смещение в строке, где начинаются интересующие числа.

3. @ChrisDodd Пробелы в формате действительно не нужны. Это хорошее улучшение, однако, не является проблемой OP в настоящее время. Пробелы удалены или нет-это проблема стиля, которую лучше всего решать в соответствии с руководством по стилю группы. Я тоже нахожу их излишними. Конечные "*…" спецификаторы полезны, если есть (и должен быть) конечный спецификатор, например " %n" , для оценки соответствия формату. if (sscanf(buffer OFFSET ... это интересная идея, но это проблема, если длина строки меньше OFFSET .