Tôi có chuỗi ký tự sau:chuỗi Progress phân tích cú pháp trong C
"..1....10..20....30...40....50...80..."
và tôi cần phải giải nén tất cả các số từ nó vào mảng.
Cách tốt nhất để làm điều đó trong C là gì?
Tôi có chuỗi ký tự sau:chuỗi Progress phân tích cú pháp trong C
"..1....10..20....30...40....50...80..."
và tôi cần phải giải nén tất cả các số từ nó vào mảng.
Cách tốt nhất để làm điều đó trong C là gì?
Có lẽ cách đơn giản nhất là sử dụng strtok()
chức năng (hoặc strtok_r()
nếu reentrancy là một mối quan tâm):
char str[] = "..1...10...20";
char *p = strtok(str, ".");
while (p != NULL) {
printf("%d\n", atoi(p));
p = strtok(NULL, ".");
}
Một khi bạn có kết quả gọi atoi()
, nó phải là một vấn đề đơn giản để lưu những số nguyên vào một mảng.
Bạn có thể sử dụng mã sscanf với phân công bị hạn chế (% * [.]) Để bỏ qua dấu chấm (hoặc bất kỳ ký tự nào khác bạn muốn), và mã số ký tự quét% n để chuyển tiếp con trỏ chuỗi.
const char *s = "..1....10..20....30...40....50...80...";
int num, nc;
while (sscanf(s, "%*[.]%d%n", &num, &nc) == 1) {
printf("%d\n", num);
s += nc;
}
Để giải quyết khiếu nại của Robert Gamble rằng điều này không xử lý các chuỗi không có dấu chấm đầu, bạn có thể chọn để viết này: trong khi (sscanf (s, "% d% n", & num, & nc) == 1 || sscanf (s, "% * [.]% d% n", & num, & nc) == 1)/* Đánh giá ngắn mạch là tuyệt vời */ – ephemient
Tôi thích sử dụng strtok trong vòng lặp for. Làm cho nó cảm thấy tự nhiên hơn, mặc dù cú pháp trông hơi kỳ lạ.
char str[] = "..1....10..20....30...40....50...80..."
for (char* p = strtok(strtok, "."); p != NULL; p = strtok(NULL, "."))
{
printf("%d\n", atoi(p));
}
Thật vậy, có vẻ khá lạ. Tôi đã có thể mong đợi một cái gì đó như cho (p = strtok (str, ","); p = strtok (NULL, ".");), Một dấu chấm phẩy sau dòng đầu tiên và một tuyên bố của p. – mweerden
Vâng - mã được viết ra khỏi đỉnh đầu của tôi. Đã sửa. –
Tôi không nghĩ rằng nó sẽ làm việc để có khởi tạo ở vị trí kiểm tra của vòng lặp for. Điều này sẽ được thực hiện mỗi khi bắt đầu vòng lặp. Tôi không nghĩ đó là những gì bạn muốn. Phiên bản của mweerden là tốt hơn, nhưng tôi sử dụng một thử nghiệm rõ ràng ở vị trí kiểm tra và di chuyển tìm nạp mã thông báo tiếp theo đến cuối. – tvanfosson
Đây là cách chính xác để thực hiện, dài hơn một chút so với cách đơn giản nhất nhưng không bị hành vi không xác định nếu giá trị đọc nằm ngoài phạm vi hoạt động chính xác. Bạn không chỉ rõ các con số có thể âm hay không vì vậy tôi đã sử dụng loại đã ký nhưng chỉ cho phép giá trị dương, bạn có thể dễ dàng thay đổi điều này bằng cách cho phép dấu âm ở đầu vòng lặp trong. Phiên bản này cho phép bất kỳ ký tự không phải chữ số nào để phân tách số nguyên, nếu bạn chỉ muốn dấu chấm được cho phép, bạn có thể sửa đổi vòng lặp bên trong để bỏ qua chỉ dấu chấm và sau đó kiểm tra chữ số.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#define ARRAY_SIZE 10
size_t store_numbers (const char *s, long *array, size_t elems)
{
/* Scan string s, returning the number of integers found, delimited by
* non-digit characters. If array is not null, store the first elems
* numbers into the provided array */
long value;
char *endptr;
size_t index = 0;
while (*s)
{
/* Skip any non-digits, add '-' to support negative numbers */
while (!isdigit(*s) && *s != '\0')
s++;
/* Try to read a number with strtol, set errno to 0 first as
* we need it to detect a range error. */
errno = 0;
value = strtol(s, &endptr, 10);
if (s == endptr) break; /* Conversion failed, end of input */
if (errno != 0) { /* Error handling for out of range values here */ }
/* Store value if array is not null and index is within array bounds */
if (array && index < elems) array[index] = value;
index++;
/* Update s to point to the first character not processed by strtol */
s = endptr;
}
/* Return the number of numbers found which may be more than were stored */
return index;
}
void print_numbers (const long *a, size_t elems)
{
size_t idx;
for (idx = 0; idx < elems; idx++) printf("%ld\n", a[idx]);
return;
}
int main (void)
{
size_t found, stored;
long numbers[ARRAY_SIZE];
found = store_numbers("..1....10..20....30...40....50...80...", numbers, ARRAY_SIZE);
if (found > ARRAY_SIZE)
stored = ARRAY_SIZE;
else
stored = found;
printf("Found %zu numbers, stored %zu numbers:\n", found, stored);
print_numbers(numbers, stored);
return 0;
}
Đầu tiên, câu trả lời đơn giản không phá vỡ nếu không có dấu chấm đầu và theo định nghĩa vì đây là phân tích cú pháp chỉ báo tiến trình, đầu vào cũng được giới hạn về phạm vi số. Sử dụng strtol() hoặc strtoul() có lẽ là một cải tiến so với atoi(), nhưng giải pháp của bạn là phức tạp không cần thiết. –
Phiên bản strtok không hoạt động trên chuỗi ký tự, không lưu trữ các số trong một mảng và sử dụng atoi có vấn đề. Các giải pháp sscanf không hoạt động mà không có dấu chấm đầu và có vấn đề tương tự như atoi. Giải pháp của tôi dài hơn nhưng nó cũng là một chương trình hoàn chỉnh với kiểm tra lỗi và bình luận. –
Tuyệt vời tôi sẽ thử điều đó! –