2010-09-21 78 views
9

Vấn đề: Tôi cần phải có thể xác định khi hai khoảng trắng xuất hiện liên tục.Làm thế nào để đọc không gian màu trắng bằng cách sử dụng scanf trong c?

Tôi đã đọc các câu hỏi sau:

how to read a string from a \n delimited file

how to read scanf with spaces

Và tôi biết vấn đề scanf: http://c-faq.com/stdio/scanfprobs.html

Input sẽ theo định dạng sau:

1 5 3 2 4 6 2 1 9 0 

Hai khoảng trắng cho biết rằng bộ dữ liệu tiếp theo cần được xử lý và so sánh với chính nó. Độ dài của dòng không xác định và số hoặc số nguyên trong mỗi nhóm không xác định. Hai khoảng trắng là phần lớn nhất sẽ tách bộ dữ liệu tiếp theo.

Trong khi tôi có thể sử dụng các hàm và các chức năng khác nhau để giải quyết vấn đề này, tôi đang ở điểm giải quyết vấn đề với scanf tại thời điểm này sẽ dễ dàng hơn. Tuy nhiên, nếu đó không phải là trường hợp, sử dụng fgets, strtok và atoi sẽ làm hầu hết công việc nhưng tôi vẫn cần phải xác định hai khoảng trắng liên tiếp.

Phần dưới đây sẽ lấy số nguyên cho đến khi một số nguyên không được nhập vào.

 
while (scanf ("%d", &x) == 1) 

Điều tôi cần làm là đọc khoảng trắng và nếu có hai khoảng trắng liên tiếp, tôi sẽ chương trình làm điều gì đó khác với tập hợp dữ liệu tiếp theo.

Và một khi tôi nhận được một không gian trắng Tôi không biết làm thế nào để nói:

 
if ((input == "whitespace") && (previousInput == "whitespace")) 
    ya da ya da 
else (input == "whitespace") 
    ya da ya da 
else 
    ya da ya da 

tôi đánh giá cao thời gian của bạn và cảm ơn bạn đã giúp đỡ của bạn.

Bài học kinh nghiệm: Trong khi một giải pháp cho scanf được đăng tải dưới đây bởi Jonathan Leffler, giải pháp là một chút đơn giản hơn với getc (bằng cách đòi hỏi kiến ​​thức ít thân mật của scanf bên trong, biểu thức thông thường và char). Nhìn lại kiến ​​thức tốt hơn về các biểu thức thông thường, scanf và char sẽ làm cho vấn đề trở nên dễ dàng hơn và tất nhiên biết những chức năng nào có sẵn và cái nào sẽ là cái tốt nhất để sử dụng ngay từ đầu.

+2

Đó là định dạng đầu vào khá ghê gớm. Nếu bạn chịu trách nhiệm về nó, hãy thiết kế lại nó. Nếu, như tôi nghi ngờ, bạn đã được giao bài tập về nhà, may mắn - họ là một nhóm tàn bạo, giáo viên của bạn. –

+3

Lưu ý rằng 'khoảng trắng' khác với 'hai khoảng trắng'; 'khoảng trắng' thông thường có nghĩa là nhiều ký tự có thể, bao gồm tab và trống (hoặc khoảng trắng) và đôi khi tạo thành nguồn cấp dữ liệu, tab dọc hoặc dòng mới; và đôi khi cũng là backspace. –

+0

@ Jonathan Leffler: ít nhất anh ấy không cố gắng phân tích Khoảng trắng (http://compsoc.dur.ac.uk/whitespace/) – ninjalj

Trả lời

6

getcungetc là bạn bè

#include <stdio.h> 

int main(void) { 
    int ch, spaces, x; 
    while (1) { 
    spaces = 0; 
    while (((ch = getc(stdin)) != EOF) && (ch == ' ')) spaces++; 
    if (ch == EOF) break; 
    ungetc(ch, stdin); 
    if (scanf("%d", &x) != 1) break; 
    printf("%d was preceded by %d spaces\n", x, spaces); 
    } 
    return 0; 
} 

Demo tại http://ideone.com/xipm1

Chỉnh sửa Rahhhhhhhhh ...Tôi đã tải lên đó là C++. Đây là điều tương tự, nhưng bây giờ C99 strict (http://ideone.com/mGeVk)

+0

scanf, sscanf, fscanf, fgets, get, getc ... lol rất nhiều tùy chọn. Tôi sẽ phải đọc trên getc và ungetc. Cảm ơn bạn đã trả lời. – MykC

+0

+1 bởi vì 'getc()' và 'ungetc()' là một cách tốt hơn để làm điều đó hơn là cố gắng sử dụng chỉ 'scanf()' - nhưng nó né tránh câu hỏi một chút. –

+4

@ MykC: ** Không, KHÔNG được! DONT EVER USE được, KHÔNG BAO GIỜ ** – pmg

1
while (scanf ("%c", &x) == 1) 

Sử dụng %c bạn có thể đọc các ký tự khoảng trống, bạn chỉ phải đọc tất cả dữ liệu và lưu trữ trong mảng. Sau đó, phân bổ char* cptr và đặt số cptr để bắt đầu mảng, sau đó bạn phân tích mảng của mình và nếu bạn muốn đọc số thập phân, bạn có thể sử dụng đơn giản sscanf trên cptr trong khi bạn muốn đọc số thập phân, nhưng bạn phải có con trỏ ở vị trí tốt trên mảng số những gì bạn wany đọc)

if (((*(cptr + 1)) == ' ') && ((*cptr)== ' ')) 
    ya da ya da 
else ((*cptr)== ' ')) 
    ya da ya da 
    sscanf(++cptr, "%d", &x); 
else 
    ya da ya da 
+0

Có vẻ tốt. Tôi tránh sử dụng con trỏ và mảng nếu tôi có thể. Lưu ý: Tôi sẽ sử dụng con trỏ và mảng khi nó làm cho cảm giác mặc dù. – MykC

+0

Tôi suy nghĩ trong một ai đó elses ý kiến ​​rằng nó xuất hiện rằng nếu có một hoặc nhiều khoảng trắng tất cả họ sẽ được lưu trữ trong một char duy nhất để dừng phương pháp trên của bạn từ làm việc. – MykC

0

Định nghĩa của bạn về 'khoảng trắng' là gì?

Thành thật mà nói, tôi không nghĩ rằng tôi muốn thử sử dụng scanf() để xác định khoảng trắng đôi; gần như mọi phương pháp khác sẽ dễ dàng hơn nhiều.

Tuy nhiên, nếu bạn nhấn mạnh vào làm không tuyệt vọng hợp lý, sau đó bạn có thể muốn sử dụng mã nguồn gốc từ như sau:

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

int main(void) 
{ 
    int d; 
    char sp[3] = ""; 
    int n; 

    while ((n = scanf("%d%2[ \t]", &d, sp)) > 0) 
    { 
     printf("n = %d; d = %d; sp = <<%s>>", n, d, sp); 
     if (n == 2 && strlen(sp) == 2) 
      printf(" end of group"); 
     putchar('\n'); 
    } 
    return 0; 
} 

Các dấu ngoặc vuông kèm theo một lớp nhân vật và 2 trước khi nó khăng khăng tại tối đa 2 ký tự trong lớp. Bạn có thể phải lo lắng về nó đọc dòng mới và cố gắng để có được nhiều dữ liệu hơn để đáp ứng các lớp nhân vật - có thể được giải quyết bằng cách loại bỏ các dòng mới từ lớp nhân vật. Nhưng sau đó nó bản lề trên định nghĩa của bạn về không gian màu trắng, và liệu các nhóm được tự động kết thúc bằng một dòng mới hay không. Sẽ không đau khi đặt lại số sp[0] = '\0'; ở cuối vòng lặp.

Bạn có thể, tốt hơn là nên đảo ngược các trường, để phát hiện hai dấu cách trước một số. Nhưng điều đó sẽ thất bại trong trường hợp thông thường, vì vậy sau đó bạn sẽ quay trở lại trên một định dạng đơn giản "%d" để đọc số (và nếu điều đó không thành công, bạn biết bạn không có không gian cũng không phải là một số - lỗi). Lưu ý rằng %d nhai không gian trắng hàng đầu (theo quy định của tiêu chuẩn) - tất cả chúng.

Tôi càng xem xét điều này, tôi càng ít thích 'scanf(). Nhắc tôi không tham gia một lớp học tại trường đại học của bạn.

+1

Tôi tin rằng tôi chỉ cần quan tâm đến bản thân mình với khoảng trống là một ký tự trống duy nhất hoặc ''. Tôi không gắn liền với scanf, tôi chỉ gắn liền với việc thực hiện nó một cách dễ dàng nhất, giả sử tôi phải làm lại và không chỉ hoàn thành công việc. Chỉ muốn xem nếu có một biểu thức regex hoặc lừa với scanf mà tôi có thể bỏ qua đó sẽ giải quyết vấn đề một cách dễ dàng một cách dễ dàng kể từ khi đầu vào được hình thành. – MykC

+0

Tôi đã xem xét câu trả lời của bạn và có vẻ như scanf trong ví dụ của bạn sẽ luôn trả về 2. Tôi hiện đang xem xét phạm vi giá trị scanf nào có thể trả về và tại sao. – MykC

+0

Tôi đã sửa, không phải lúc nào cũng trả lại 2. – MykC

0

Nếu bạn thực sự muốn scanf chức năng loại, bạn có thể sử dụng fgetssscanf, và sử dụng %n specifier để có được scanf để cung cấp cho chương trình của bạn offsets cho sự khởi đầu và kết thúc của mỗi khoảng thời gian khoảng trắng cùng một lúc nó hiện phần còn lại công việc của nó.

Nếu không, hãy bỏ qua toàn bộ gia đình scanf. Nó hoàn toàn có thể là phần vô dụng nhất của thư viện chuẩn, theo ý kiến ​​của tôi.

+0

Nó hữu ích, nhưng nói chung là xấu. Nếu bạn muốn thêm đầu vào tương đương với một lệnh in gỡ lỗi vào một chương trình, thì nó rất tuyệt. Nếu bạn muốn thêm đầu vào đơn giản cho một chương trình thử nghiệm hoặc trình diễn (nơi thực hành đầu vào tốt không phải là những gì bạn đang demo), sau đó nó khá tốt. Nếu bạn muốn làm đầu vào cho mã sản xuất nó thực sự xấu. – nategoose

+0

Trên thực tế có một cách sử dụng cho 'scanf': một phiên bản di động của' getline' (hoặc 'getdelim'), bao gồm xử lý sạch các ký tự NUL được nhúng, có thể đạt được với một cái gì đó như' scanf ("% 99 [^ \ n] % n ", buf, &cnt);' (trong đó 99 được thay thế bằng kích thước bộ đệm của bạn) –

+0

'scanf ("% 99 [^ \ n]% n ", buf, &cnt);' có vấn đề là nó không lưu gì vào 'buf' và 'cnt' nếu đầu vào bắt đầu bằng' '\ n'' và để lại '' \ n'' trong stdin. Điều này không giống 'getline()'. – chux

0

Đây là giải pháp chỉ sử dụng hàm scanf(). Tôi đã sử dụng sscanf() trong mẫu này cho cùng một chức năng.

#include <stdio.h> 


int p_1_cnt = 0, p_2_cnt = 0; 

void process_1(int x) 
{ 
    p_1_cnt++; 
} 


void process_2(int x) 
{ 
    p_2_cnt++; 
} 


char * input_line = "1 5 3 2 4 6 2 1 9 0"; 

int main(void) 
{ 
    char * ip = input_line; 

    int x = 0, ws_0 = 0, ws_1 = 0, preceding_spaces = 1, fields = -2; 

    while (sscanf (ip, "%d%n %n", &x, &ws_0, &ws_1) > 0) 
    { 
     ip += ws_0; 

     if ((preceding_spaces) == 1) 
      process_1(x); 
     else 
      process_2(x); 

     preceding_spaces = ws_1 - ws_0; 
    } 

    printf("\np_1_cnt = %d, p_2_cnt = %d", p_1_cnt, p_2_cnt); 
    _fgetchar(); 

    return 0; 
}