2009-12-23 50 views
5

Tôi đã có một số mã để đọc một tệp văn bản bằng cách sử dụng fscanf() và bây giờ tôi cần nó được sửa đổi để các trường trước đây không cần khoảng trắng cần cho phép khoảng trắng. Các tập tin văn bản về cơ bản là theo hình thức:Có thể fscanf() đọc khoảng trắng không?

tiêu đề: DATA
tiêu đề: DATA
vv ...

đó là cơ bản phân tích cú pháp sử dụng fgets(inputLine, 512, inputFile); sscanf(inputLine, "%*s %s", &data);, đọc các lĩnh vực DATA và bỏ qua các tiêu đề, nhưng bây giờ một số trường dữ liệu cần cho phép các khoảng trống. Tôi vẫn cần phải bỏ qua tiêu đề và khoảng trống ngay lập tức sau nó, nhưng sau đó đọc phần còn lại của dòng bao gồm khoảng trắng.

Có cách nào để thực hiện việc này với chức năng sscanf() không?

Nếu không, thay đổi nhỏ nhất mà tôi có thể thực hiện cho mã để xử lý khoảng trắng chính xác là gì?

CẬP NHẬT: Tôi đã chỉnh sửa câu hỏi để thay thế fscanf() bằng fgets() + sscanf(), mã của tôi thực sự đang sử dụng. Tôi đã không thực sự nghĩ rằng nó có liên quan khi tôi lần đầu tiên đã viết câu hỏi đó là lý do tại sao tôi đơn giản hóa nó để fscanf().

+0

Nếu bạn đã từng phân tích cú pháp bằng cách sử dụng 'scanf', thì trước đó bạn cũng có thể phân tích cú pháp một cái gì đó như' tiêu đề: DATA title: DATA' (nghĩa là tất cả trên một dòng). Nếu bạn muốn cho phép khoảng trắng trong các giá trị, thì điều gì sẽ là trình kết thúc? Nếu newline, sau đó có vẻ như mã ban đầu của bạn hơi quá lỏng lẻo ... –

+0

Ngoài ra, làm thế nào để bạn quyết định kích thước của bộ đệm 'str', và làm thế nào để bạn đảm bảo rằng nó không tràn? –

+0

có, khi DATA có thể có khoảng trống dòng mới sẽ được sử dụng làm terminator –

Trả lời

11

Nếu bạn không thể sử dụng fgets() sử dụng specifier %[ chuyển đổi (với "tùy chọn loại trừ"):

char buf[100]; 
fscanf(stdin, "%*s %99[^\n]", buf); 
printf("value read: [%s]\n", buf); 

Nhưng fgets() là cách tốt hơn.


Edit: phiên bản với fgets() + sscanf()

char buf[100], title[100]; 
fgets(buf, sizeof buf, stdin); /* expect string like "title: TITLE WITH SPACES" */ 
sscanf(buf, "%*s %99[^\n]", title); 
+3

Đối với trường hợp cụ thể này, làm thế nào là 'fgets'" cách tốt hơn "? –

+1

Vâng ... các yêu cầu tiếp tục thay đổi (đầu tiên không có không gian trong chuỗi). Nó không phải là tốt hơn cho trường hợp cụ thể này, nhưng tốt hơn là sử dụng 'fgets()' bây giờ, trong antecipation cho sự thay đổi tiếp theo của yêu cầu :) – pmg

+0

Tôi cập nhật câu hỏi để cho thấy rằng tôi thực sự sử dụng fgets() để đọc dòng, sau đó sscanf() để phân tích nó, nhưng là có một cách tốt hơn để phân tích các dòng sau khi fgets()? –

3

Tôi khuyên bạn nên ngừng sử dụng fscanf() và bắt đầu sử dụng fgets() (đọc toàn bộ dòng) và sau đó phân tích cú pháp dòng đã được đọc.

Điều này sẽ cho phép bạn tự do hơn đáng kể liên quan đến phân tích cú pháp đầu vào không được định dạng chính xác.

+0

Tôi đã cập nhật câu hỏi để cho thấy rằng tôi thực sự sử dụng fgets(), nhưng tôi không hiểu chính xác nó sẽ giúp ích gì. Tôi vẫn phải phân tích dòng khi tôi đọc nó. –

+1

Một khi bạn đã có toàn bộ chuỗi, hãy tự mình đi bộ thay vì sử dụng sscanf. –

+0

Có, làm điều đó với con trỏ, hoặc thậm chí tốt hơn sử dụng biểu thức thông thường. Nếu bạn sử dụng C++ tôi đã đề xuất tăng; Tôi không biết bất kỳ thư viện C nào tốt nhưng phải có một số thư viện. Tôi nghe nói POSIX hỗ trợ họ. –

2

Điều đơn giản nhất sẽ phát hành một

fscanf("%*s"); 

để loại bỏ phần đầu và sau đó chỉ cần gọi fgets:

fgets(str, stringSize, filePtr); 
3

Nếu bạn nhấn mạnh vào việc sử dụng scanf, và giả định rằng bạn muốn xuống dòng như một terminator, bạn có thể làm điều này:

scanf("%*s %[^\n]", str); 

Lưu ý, tuy nhiên, ở trên, được sử dụng chính xác như được viết, là một ý tưởng tồi vì thứ Không có gì để bảo vệ chống lại str bị tràn ngập (vì scanf không biết kích thước của nó). Bạn có thể, tất nhiên, thiết lập một kích thước tối đa được xác định trước, và xác định đó, nhưng sau đó chương trình của bạn có thể không hoạt động chính xác trên một số đầu vào hợp lệ.

Nếu kích thước của dòng, như được định nghĩa bởi định dạng đầu vào, không giới hạn, thì tùy chọn thực tế duy nhất của bạn là sử dụng fgetc để đọc dữ liệu char theo char, định kỳ tái phân bổ bộ đệm khi bạn đi. Nếu bạn làm điều đó, sau đó sửa đổi nó để thả tất cả các ký tự đọc cho đến khi khoảng trắng đầu tiên là khá tầm thường.

2

A %s thông số kỹ thuật trong fscanf bỏ qua bất kỳ khoảng trống nào trên đầu vào, sau đó đọc một chuỗi ký tự không khoảng trắng và không bao gồm ký tự khoảng trắng tiếp theo.

Nếu bạn muốn đọc đến một dòng mới, bạn có thể sử dụng %[^\n] làm người chỉ định. Ngoài ra, một '' trong chuỗi định dạng sẽ bỏ qua khoảng trống trên đầu vào. Vì vậy, nếu bạn sử dụng

fscanf("%*s %[^\n]", &str); 

nó sẽ đọc điều đầu tiên trên dòng lên đến khoảng trắng đầu tiên ("title:" trong trường hợp của bạn), và vứt nó đi, sau đó sẽ đọc ký tự khoảng trắng và ném chúng đi, sau đó sẽ đọc tất cả các ký tự lên đến một dòng mới vào str, mà âm thanh như những gì bạn muốn.

Hãy cẩn thận rằng str không tràn - bạn có thể muốn sử dụng

fscanf("%*s %100[^\n]", &str) 

để hạn chế độ dài chuỗi tối đa mà bạn sẽ đọc (100 ký tự, không kể một NUL chấm dứt ở đây).

+0

Tôi biết đây là một đoạn ngắn ví dụ nhưng bạn phải sử dụng địa chỉ của str? Tôi nghĩ điều này cũng sẽ hiệu quả. 'fscanf ("% * s% [^ \ n] ", str);' – cokedude

1

Bạn đang chạy lên chống lại các giới hạn của những gì mà các gia đình *scanf là tốt cho. Với những thay đổi khá nhỏ, bạn có thể thử sử dụng các mô-đun quét chuỗi từ số C Interfaces and Implementations của Dave Hanson. Công cụ này được trang bị thêm từ ngôn ngữ lập trình Icon, một ngôn ngữ xử lý chuỗi cực kỳ đơn giản và mạnh mẽ mà Hanson và những người khác đã làm việc tại Arizona. Sự ra đi từ sscanf sẽ không quá nghiêm trọng và nó đơn giản hơn, dễ làm việc hơn và mạnh hơn các cụm từ thông dụng. Mặt duy nhất xuống là mã là một chút khó khăn để làm theo mà không có cuốn sách — nhưng nếu bạn làm nhiều lập trình C, cuốn sách cũng có giá trị.

Các vấn đề liên quan