Как отделить строки от целых чисел в c [duplicate]

Вот реальный пример, над которым я сейчас работаю, от систем обработки / управления сигналами:

Предположим, что у вас есть структура, которая представляет данные, которые вы собираете:

struct Sample {
    time_t time;
    double value1;
    double value2;
    double value3;
};

Теперь предположим, что вы введете их в вектор:

std::vector<Sample> samples;
... fill the vector ...

Теперь предположим, что вы хотите вычислить некоторую функцию (скажем, среднее значение) одной из переменных в диапазоне выборок, а вы хотите, чтобы этот средний расчет включал функцию. Указатель-к-член упрощает:

double Mean(std::vector<Sample>::const_iterator begin, 
    std::vector<Sample>::const_iterator end,
    double Sample::* var)
{
    float mean = 0;
    int samples = 0;
    for(; begin != end; begin++) {
        const Sample& s = *begin;
        mean += s.*var;
        samples++;
    }
    mean /= samples;
    return mean;
}

...
double mean = Mean(samples.begin(), samples.end(), &Sample::value2);

Примечание Редактировано 2016/08/05 для более сжатого подхода к шаблону-функции

И, конечно, вы можете использовать шаблон это вычислить среднее значение для любого форварда-итератора и любого типа значения, который поддерживает добавление с самим собой и деление на size_t:

template<typename Titer, typename S>
S mean(Titer begin, const Titer& end, S std::iterator_traits<Titer>::value_type::* var) {
    using T = typename std::iterator_traits<Titer>::value_type;
    S sum = 0;
    size_t samples = 0;
    for( ; begin != end ; ++begin ) {
        const T& s = *begin;
        sum += s.*var;
        samples++;
    }
    return sum / samples;
}

struct Sample {
    double x;
}

std::vector<Sample> samples { {1.0}, {2.0}, {3.0} };
double m = mean(samples.begin(), samples.end(), &Sample::x);

EDIT - приведенный выше код имеет последствия для производительности

Вы следует отметить, как я вскоре обнаружил, что приведенный выше код имеет некоторые серьезные последствия для производительности. Резюме состоит в том, что если вы вычисляете итоговую статистику по временному ряду или вычисляете FFT и т. Д., То вы должны хранить значения для каждой переменной в памяти. В противном случае итерация по ряду приведет к пропуску кеша для каждого полученного значения.

Рассмотрим производительность этого кода:

struct Sample {
  float w, x, y, z;
};

std::vector<Sample> series = ...;

float sum = 0;
int samples = 0;
for(auto it = series.begin(); it != series.end(); it++) {
  sum += *it.x;
  samples++;
}
float mean = sum / samples;

На многих архитектурах один экземпляр Sample будет заполнять строку кэша. Таким образом, на каждой итерации цикла один образец будет извлечен из памяти в кеш. 4 байта из строки кэша будут использоваться, а остальные будут удалены, а следующая итерация приведет к еще одному пропуску кэша, доступу к памяти и т. Д.

Гораздо лучше сделать это:

struct Samples {
  std::vector<float> w, x, y, z;
};

Samples series = ...;

float sum = 0;
float samples = 0;
for(auto it = series.x.begin(); it != series.x.end(); it++) {
  sum += *it;
  samples++;
}
float mean = sum / samples;

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

Вышеупомянутый алгоритм может быть несколько улучшен за счет использования SIMD-инструкций, например, для архитектур SSE2. Тем не менее, они работают намного лучше, если значения все смежны в памяти, и вы можете использовать одну инструкцию для загрузки четырех образцов вместе (подробнее в последующих версиях SSE).

YMMV - проектируйте свои структуры данных в соответствии с вашими алгоритм.

13
задан CDT 15 November 2012 в 16:29
поделиться

6 ответов

Вы можете сделать это с помощью strtol , например:

char *str = "ab234cid*(s349*(20kd", *p = str;
while (*p) { // While there are more characters to process...
    if ( isdigit(*p) || ( (*p=='-'||*p=='+') && isdigit(*(p+1)) ) {
        // Found a number
        long val = strtol(p, &p, 10); // Read number
        printf("%ld\n", val); // and print it.
    } else {
        // Otherwise, move on to the next character.
        p++;
    }
}

Ссылка на ideone .

22
ответ дан DevSolar 3 September 2018 в 14:01
поделиться

Сделать конечный автомат, который работает по одному основному принципу: текущий символ - номер.

  • При переходе от нецифровой к цифре вы инициализируете свой номер текущего_ номера: =.
  • при переходе от цифры к цифре вы «сдвигаете» новую цифру в: current_number: = current_number * 10 + number;
  • при переходе от цифры к несимвольной, вы выводите current_number
  • , когда от нецифровой до нецифровой, вы ничего не делаете.

Возможны оптимизации.

1
ответ дан Aki Suihkonen 3 September 2018 в 14:01
поделиться

Или вы можете сделать простую функцию следующим образом:

// Provided 'c' is only a numeric character
int parseInt (char c) {
    return c - '0';
}
0
ответ дан Divyanshu Kushwaha 3 September 2018 в 14:01
поделиться

Возможное решение с использованием sscanf() и наборов сканирования:

const char* s = "ab234cid*(s349*(20kd";
int i1, i2, i3;
if (3 == sscanf(s,
                "%*[^0123456789]%d%*[^0123456789]%d%*[^0123456789]%d",
                &i1,
                &i2,
                &i3))
{
    printf("%d %d %d\n", i1, i2, i3);
}

, где %*[^0123456789] означает игнорировать ввод до тех пор, пока не будет найдена цифра. См. Демонстрацию в http://ideone.com/2hB4UW .

Или, если число номеров неизвестно, вы можете использовать спецификатор %n для записи последней позиции, прочитанной в буфер:

const char* s = "ab234cid*(s349*(20kd";
int total_n = 0;
int n;
int i;
while (1 == sscanf(s + total_n, "%*[^0123456789]%d%n", &i, &n))
{
    total_n += n;
    printf("%d\n", i);
}
12
ответ дан hmjd 3 September 2018 в 14:01
поделиться

здесь после простого решения с использованием sscanf:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

char str[256]="ab234cid*(s349*(20kd";
char tmp[256];

int main()
{

    int x;
    tmp[0]='\0';
    while (sscanf(str,"%[^0123456789]%s",tmp,str)>1||sscanf(str,"%d%s",&x,str))
    {
        if (tmp[0]=='\0')
        {
            printf("%d\r\n",x);
        }
        tmp[0]='\0';

    }
}
2
ответ дан MOHAMED 3 September 2018 в 14:01
поделиться

Если числа разделены пробелом в строке, вы можете использовать sscanf (). Так как это не так с вашим примером, вы должны сделать это сами:

char tmp[256];

for(i=0;str[i];i++)
{
  j=0;
  while(str[i]>='0' && str[i]<='9')
  {
     tmp[j]=str[i];
     i++;
     j++;
  }
  tmp[j]=0;
  printf("%ld", strtol(tmp, &tmp, 10));
  // Or store in an integer array

}

1
ответ дан P.P. 3 September 2018 в 14:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: