Как проверить, успешно ли выполнена команда R при использовании RInside - PullRequest
4 голосов
/ 19 февраля 2020

Я хочу написать программу для выполнения команды R с использованием RInside и сказать, является ли результат строкой. Я создал экземпляр RInside и использовал его метод RInside :: parseEval для анализа команды R, а затем сохранил результат в переменной SEXP. Я использовал TYPEOF , чтобы проверить, является ли тип результата строкой, и затем преобразовал его в R cpp :: String , используя его конструктор . Проблема в том, что когда я пытаюсь разобрать команду ошибки, такую ​​как paste('hello, поведение программы становится несколько непредсказуемым. Программа показана ниже:

#include <RInside.h>
#include <stdio.h>

int main(int argc, char* argv[])
{

        RInside *R = new RInside();
        const char *expr = argv[1];

        SEXP res = NULL;
        try{
                res = R->parseEval(expr);
        } catch (std::exception &e) {
                res = NULL;
                printf("Exception thrown\n");
        }

        printf("res points to %p\n", res);
        if (res != NULL && TYPEOF(res) == STRSXP) {
                Rcpp::String res_str = res;
                printf("The result is a string: %s\n", res_str.get_cstring());
        } else {
                printf("The result is not a string");
        }
}

Когда я запустил программу с агрументом "paste('hello'", я получил вывод

res точек 0x7f0ca84e14d0

Результат не является строкой

Однако, когда я упаковал код в функцию, как показано:

#include <RInside.h>
#include <stdio.h>

void test_R(RInside *R, const char *expr)
{
        SEXP res = NULL;
        try{
                res = R->parseEval(expr);
        } catch (std::exception &e) {
                res = NULL;
                printf("Exception thrown\n");
        }

        printf("res points to %p\n", res);
        if (res != NULL && TYPEOF(res) == STRSXP) {
                Rcpp::String res_str = res;
                printf("The result is a string: %s\n", res_str.get_cstring());
        } else {
                printf("The result is not a string");
        }
}

int main(int argc, char* argv[])
{

        RInside *R = new RInside();
        const char *expr = argv[1];

        test_R(R, expr);
}

и запустил ее с тем же аргументом командной строки "paste('hello'" как и раньше, я получил вывод

res указывает на (ноль)

Результат не является строкой

Так что мой вопрос, почему так себя вести? Когда кто-то анализирует команду ошибки с RInside::parseEval, будет ли сгенерировано исключение, или результатом будет нулевой указатель, или произойдет хотя бы один из этих случаев? Правильно ли работает мой код выше?

Любая помощь будет благодарна.

Edit 0:

Потратив некоторое время на чтение кода, кажется, что R обрабатывает команда paste('hello как «неполная», что означает, что если мы позже отправим другую команду, чтобы «завершить» ее, она будет успешно выполнена.

#include <RInside.h>
#include <stdio.h>

void test_R(RInside *R, const char *expr, int is_ok)
{
        SEXP res = R->parseEval(expr);
        if (is_ok) {
                std::string res_str = Rcpp::String(res);
                printf("The result is %s\n", res_str.c_str());
        }
}

int main()
{

        RInside R;
        const char *head = "paste('hello";
        const char *tail = "')";

        test_R(&R, head, 0); // This will parse "paste('hello"
        test_R(&R, tail, 1); // This will parse the rest of the command
}

Результат приведенного выше кода равен

Результат привет

...