LINUX.ORG.RU

Вырезание строки в чистом си


0

3

Есть текстовый файл со строками вида:

0.000315625,1,DATA,0x10210046,0x8,0x01 0x4A 0x00 0x79 0x0A 0xB3 0x00 0x01,0x6208,ACK
0.000458,2,DATA,0x10210046,0x8,0x00 0x01 0xFF 0xFB 0x00 0x05 0x00 0x01,0x7092,ACK
0.00203325,3,DATA,0x00400003,0x8,0x05 0x05 0x05 0x05 0x05 0x05 0x05 0x05,0x492A,ACK

Нужно считать шестнадцатиричные значения только жирной части:

0.000315625,1,DATA,0x10210046,0x8,0x01 0x4A 0x00 0x79 0x0A 0xB3 0x00 0x01,0x6208,ACK

Возможно ли это на чистом си со стандартными библиотеками. Пробовал подогнать форматирование fscanf'ом - не вышло.


можно шелл-скрипт забацать или на С надо?

UVV ★★★★★
()

Путем поиска n-ой запятой (strchr) найти начало последовательности. Ну а потом хоть через sscanf, хоть через strtol.

Dead ★★★★
()
Последнее исправление: Dead (всего исправлений: 1)
Ответ на: комментарий от joy4eg

Инкрементирую. При помощи strchr выделяем текст между пятой и шестой запятыми, потом при помощи strtok бьем на куски по пробелам и считываем.

Anon
()

Возможно ли это на чистом си со стандартными библиотеками. Пробовал подогнать форматирование fscanf'ом - не вышло.

WAT

#include <stdio.h>

int main(void)
{
    const char *entry = "0.000315625,1,DATA,0x10210046,0x8,0x01 0x4A 0x00 0x79 0x0A 0xB3 0x00 0x01,0x6208,ACK";
    unsigned values[8];
    sscanf(entry, "%*f,%*d,DATA,%*x,0x8,%x %x %x %x %x %x %x %x,%*x,ACK",
           values + 0, values + 1, values + 2, values + 3,
           values + 4, values + 5, values + 6, values + 7);
    printf("0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
           values[0], values[1], values[2], values[3],
           values[4], values[5], values[6], values[7]);
}
theNamelessOne ★★★★★
()

Пробовал подогнать форматирование fscanf'ом - не вышло

с этого места подробнее - как пытался подогнать и что конкретно не вышло

MKuznetsov ★★★★★
()
#include <stdio.h>

void main () {
        char *s="0.000315625,1,DATA,0x10210046,0x8,0x01 0x4A 0x00 0x79 0x0A 0xB3 0x00 0x01,0x6208,ACK";

        char *s2[255];
        float f; int i,j,k;
        unsigned char hexes[8];
        sscanf(s, "%f,%d,DATA,%x,%x,%i%i%i%i%i%i%i%i,%s", &f,&i,&j,&k,&hexes[0],&hexes[1],&hexes[2],&hexes[3],&hexes[4],&hexes[5],&hexes[6],&hexes[7],s2);
        printf("%x\n", hexes[7]);

}

все можно с scanf, хоть и не так красиво. Но может знатоки поправят. можно еще красивее, если в цикле делать. но если строки остаются именно такими, как ты описал, то смысла городить циклы нет, ибо и так работать будет.

dikiy ★★☆☆☆
()
Последнее исправление: dikiy (всего исправлений: 3)
Ответ на: комментарий от dikiy

setlocale(LC_ALL, ""); установит системную локаль (в соответствии с переменными окружения), в которой как раз разделителем может оказаться запятая. Нужно устанавливать локали «C» или «POSIX», у них , ЕМНИП, точно разделитель — точка.

Локаль «C» вручную устанавливать не нужно, она выбирается по умолчанию при старте программы.

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 1)
Ответ на: комментарий от Anon

Я к тому, что в системе у меня так:

locale
LANG=ru_RU.koi8-r
LC_CTYPE="ru_RU.koi8-r"
LC_NUMERIC=C
LC_TIME="ru_RU.koi8-r"
LC_COLLATE="ru_RU.koi8-r"
LC_MONETARY="ru_RU.koi8-r"
LC_MESSAGES="ru_RU.koi8-r"
LC_PAPER="ru_RU.koi8-r"
LC_NAME="ru_RU.koi8-r"
LC_ADDRESS="ru_RU.koi8-r"
LC_TELEPHONE="ru_RU.koi8-r"
LC_MEASUREMENT="ru_RU.koi8-r"
LC_IDENTIFICATION="ru_RU.koi8-r"
LC_ALL=
и все ОК с датами, текстами и числами.

// вот, кстати, интересно: откуда взялся этот идиотский стандарт на использование разделителя полей списка (",") в качестве десятичной точки?

Anon
()
Ответ на: комментарий от Anon

вот, кстати, интересно: откуда взялся этот идиотский стандарт на использование разделителя полей списка (",") в качестве десятичной точки?

исторически так сложилось. Открываю Фихта за 1959 год и вижу там именно запятую как десятичный разделитель.

dikiy ★★☆☆☆
()
Ответ на: комментарий от Anon

Да, LC_NUMERIC=C достаточно, LC_ALL же была в сообщении, на которое я отвечал.

theNamelessOne ★★★★★
()
Ответ на: комментарий от Anon

откуда взялся этот идиотский стандарт на использование символа окончания предложения (".") в качестве десятичного разделителя

fixed

anonymous
()
Ответ на: комментарий от anonymous

Протестируйте следующий код

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

// Global data
char buf[200];		/* input line buffer */
char *field[20];	/* fields */
//

// Functions
int csvgetline(FILE *fin);
char* unquote(char *p);
//

/* csvgetline: read and parse line, return field count */
/* sample input: "LU",86.25,"11/4/1998","2:19PM",+4.0625 */
int csvgetline(FILE *fin)
{	
	int nfield=0;
	char *p, *q;
																															/* spacer */
	if (fgets(buf, sizeof(buf), fin) == NULL)
		return -1;
	nfield = 0;
	for (q = buf; (p=strtok(q, ",\n\r")) != NULL; q = NULL)
		field[nfield++] = p; //unquote(p);
	return nfield;
}

/* unquote: remove leading and trailing quote */
char *unquote(char *p)
{
	if (p[0] == '"') {
		if (p[strlen(p)-1] == '"')
			p[strlen(p)-1] = '\0';
		p++;
	}
	return p;
}

int main(int argc, char *argv[])
{
	FILE * fp;
	int i, nf;
	char outData[100]="";

    if (argc < 2) 
	{
        printf("Usage: parse_hex_data [datafile] \n"
        	   "Parse data files\n");
        return 1;
    }
    
	fp = fopen( argv[1], "r" );
	if( fp == NULL ) {
		fputs("Error open data file \n", stderr);
		exit(1);
	}
	while ((nf = csvgetline(fp)) != -1)  
	{
		printf("%s\n",field[5]);  // ????????

		for (i = 0; i < nf; i++) 
		{
			strcat(outData," ");
			strcat(outData,field[i]);
		}
		printf("%s\n",outData);
		outData[0]='\0';
			
	}	
	fclose(fp);
	return 0;
}

Где знаки вопроса ваше значение.

anonymous
()
Ответ на: комментарий от anonymous

Всем спасибо! Реализовал мысль theNamelessOne. Программулина нужна была быстро и тут уже не до красоты кода. Конечная цель была преобразовать эти шестнадцатиричные значения преборазовать в int16 и вывести в файл.

Dzusan
() автор топика
Ответ на: комментарий от anonymous

На твоем же тестовом примере твоя программа падает.

anonymous
()
Ответ на: комментарий от Dzusan

Конечная цель была преобразовать эти шестнадцатиричные значения в int16 и вывести в файл.

Так и надо было сразу это озвучить вместо того, чтобы сбивать общественность с толку «чистым Си».

Вместо простыней кода на Си отделались бы парой строчек на awk.

Например, чтобы из восьми октетов в шестнадцатеричной нотации в каждой строке исходных данных получить четыре int16 в десятичной системе, полагая, что исходные данные были в big-endian, достаточно такой команды.

awk -F'[, ]' '{ for (i = 0; i < 4; i++) { x = 0; for (j = 0; j < 2; j++) x += $(i*2 + j + 6) * 256^(1 - j); printf("%u\n", x) } print "" }' test.txt
unterwulf
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.