CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.
Bài viết blog CFSDN này C++ tạo mã ví dụ chuỗi tiêu chuẩn được định dạng được tác giả sưu tầm và biên soạn. Nếu bạn quan tâm đến bài viết này, hãy nhớ thích nó.
Hai phương pháp định dạng chuỗi.
Như chúng ta đã biết, std::string của C++ có các chức năng chưa hoàn chỉnh và không có nhiều chức năng khác nhau, chẳng hạn như các hàm định dạng chuỗi.
Trong python3, hai phương thức định dạng chuỗi được hỗ trợ, một là kiểu C, phần định dạng bắt đầu bằng % và % sau tương ứng với loại cụ thể (ví dụ: %s tương ứng với chuỗi %d tương ứng với số nguyên), và cái còn lại Kiểu đầu tiên là kiểu không phụ thuộc vào loại, {0} tương ứng với tham số đầu tiên và {1} tương ứng với tham số thứ hai.
?
1
2
3
4
|
>>>
"Tuổi của {0} là {1}"
.định dạng(
"đỏ thẫm"
, 11)
"Chihong tuổi là 11"
>>>
"Tuổi của %s là %d"
% (
"đỏ thẫm"
, 11)
"Chihong tuổi là 11"
|
Trong C++, bạn chỉ có thể mượn các hàm C và sử dụng snprintf để định dạng bộ đệm.
?
1
2
3
|
#define KÍCH THƯỚC BUFFS 512
char
buf[KÍCH THƯỚC BUFFS];
snprintf(buf, KÍCH THƯỚC BUFFS,
"Tuổi của %s là %d\n"
,
"đỏ thẫm"
, 11);
|
Hoặc sử dụng toán tử luồng độc lập với loại.
?
1
2
3
|
std::ostringstream os;
trục <<
"đỏ thẫm"
<<
"Tuổi của là "
<< 11 <<
"\N"
;
std::string s = os.str();
|
Tạm thời đặt vấn đề về hiệu quả sang một bên, phương pháp sử dụng << này để ghép nhiều đối tượng thuộc các loại khác nhau đòi hỏi một lượng lớn mã và việc kiểm soát định dạng đầu ra cụ thể sẽ rắc rối hơn, chẳng hạn như kiểm soát số chữ số bị chiếm dụng bằng một số hoặc số chữ số thập phân. Ít nhất thì nó phức tạp đến mức tôi không thể luôn nhớ nó. Tôi muốn sử dụng snprintf kiểu C để kiểm soát nó. Ví dụ.
?
1
2
|
gấp đôi
d = 3,1415926;
snprintf(buf, KÍCH THƯỚC BUFFS,
"Pi: %-8.3lf được Zu Chongzhi phát hiện\n"
, d);
|
?
1
2
|
$ ./a.ra
Pi: 3.142 được phát hiện bởi Zu Chongzhi
|
Sử dụng %-8.3lf để đặt số dấu phẩy động loại lf (dài hoặc gấp đôi) thành 8, đặt số chữ số sau dấu thập phân thành 3 và dấu âm có nghĩa là căn lề trái. .
Về việc triển khai bằng tệp tiêu đề iomanip của C++, tôi cũng dành chút thời gian kiểm tra tài liệu.
?
1
2
3
4
|
gấp đôi
d = 3,1415926;
trục <<
"Pi:"
<< std::setw(8) << std::fixed
<< std::setprecision(3) << std::left
<< ngày <<
"Nó được phát hiện bởi Zu Chongzhi\n"
;
|
Ngoài việc mã quá dài và có khả năng thiếu std::fixed, vấn đề là setprecision đã thay đổi cài đặt mặc định, nghĩa là nếu os << chuyển vào số dấu phẩy động thì số dấu thập phân được giữ lại là vẫn là 3 Bit.
Một số người có thể nói rằng ưu điểm là setprecision và setw có thể nhận một biến thay vì một hằng số. Thực tế, snprintf cũng có thể làm được điều tương tự.
?
1
2
3
|
gấp đôi
d = 3,1415926;
số nguyên
n1 = 8, n2 = 3;
snprintf(buf, KÍCH THƯỚC BUFFS,
"Pi: %-*.*lf được Zu Chongzhi phát hiện\n"
, n1, n2, d);
|
Trình bao bọc C++ snprintf tạo ra các đối tượng chuỗi std::được định dạng.
Trong APUE UNP TLPI, một số cuốn sách về lập trình C trên Linux, tất cả đều viết thư viện xử lý lỗi của riêng mình để bọc snprintf nhằm tạo ra đầu ra được định dạng, nhằm tránh việc xác định nhiều lần bộ đệm/gọi snprintf, v.v. mỗi lần.
Một nhược điểm của phương pháp này là độ dài của bộ đệm (mảng ký tự) bị hạn chế. Tất nhiên, nói chung, nếu kích thước bộ đệm được xác định đủ lớn thì việc in một chuỗi được định dạng quá dài là đủ. không tốt bằng việc gọi hàm nhiều lần.
Mặt khác, vì các chức năng này chỉ in thông tin, đặc biệt nếu bạn thường xuyên in thông tin rồi thoát trực tiếp khỏi chương trình. Vì vậy, không có chuỗi lỗi nào sẽ được trả lại. Nếu bạn muốn chuyển thông tin lỗi dưới dạng ngoại lệ lên lớp trên để xử lý trong C++ thì những chức năng này là không đủ. Vì vậy, nó cần phải được sửa đổi một cách đơn giản.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
nội tuyến
std::string định dạng_chuỗi(
hằng số
char
* định dạng,
va_list
đối số) {
constexpr
kích thước_t
oldlen = KHÔNG CÓ BUFF;
char
buffer[oldlen];
va_list
đối số;
va_copy(đối số, đối số);
kích thước_t
newlen = vsnprintf(&buffer[0], oldlen, định dạng, đối số) + 1;
mới++;
nếu như
(newlen > oldlen) {
std::vector<
char
> newbuffer(newlen);
vsnprintf(newbuffer.data(), newlen, định dạng, argscopy);
trở lại
newbuffer. dữ liệu();
}
trở lại
đệm;
}
nội tuyến
std::string định dạng_chuỗi(
hằng số
char
* định dạng, ...) {
va_list
các đối số;
va_start
(đối số, định dạng);
tự động s = chuỗi định dạng(định dạng, đối số);
đi_kết thúc
(đối số);
trở lại
S;
}
|
Đây là một triển khai bắt chước UNP. Các tham số chính thức được xác định là hai phiên bản của va_list và.... Phiên bản chấp nhận va_list cũng có thể được sử dụng bởi các chức năng khác. Bởi vì danh sách đối số biến đổi kiểu C...không thể được chuyển làm đối số. Một điểm nữa là kiểu va_list không nhất thiết phải có hàm khởi tạo sao chép nên bạn phải sử dụng va_copy để sao chép một va_list cho lần sử dụng thứ hai.
C++ 11 bổ sung thêm tính năng tham số mẫu biến mới, cho phép đơn giản hóa đoạn mã trên.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
bản mẫu
<
tên kiểu chữ
...Đối số>
nội tuyến
std::string định dạng_chuỗi(
hằng số
char
* định dạng, Args... args) {
constexpr
kích thước_t
oldlen = KHÔNG CÓ BUFF;
char
buffer[oldlen];
kích thước_t
newlen = snprintf(&buffer[0], oldlen, định dạng, đối số...);
mới++;
nếu như
(newlen > oldlen) {
std::vector<
char
> newbuffer(newlen);
snprintf(newbuffer.data(), newlen, định dạng, đối số...);
trở lại
std::string(newbuffer. dữ liệu());
}
trở lại
đệm;
}
|
Việc chuyển các tham số mẫu biến đổi cũng rất dễ dàng (sử dụng chuyển tiếp để chuyển tiếp hoàn hảo).
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
xyz@ubuntu:~/unp_practice/lib$ kiểm tra cat.cc
#include
#include
#include "format_string.h"
bản mẫu
<
tên kiểu chữ
...Đối số>
vô hiệu
errExit(
hằng số
char
* định dạng, Args... args) {
tự động errmsg = chuỗi định dạng(định dạng, std::forward(args)...);
errmsg = errmsg +
": "
+
lỗi liên tục
(
lỗi
) +
"\N"
;
đầu ra
(errmsg.c_str(), lỗi chuẩn);
ra
(1);
}
số nguyên
chủ yếu() {
hằng số
char
* s =
"Xin chào thế giới!"
;
số nguyên
fd = -1;
nếu như
(viết(fd, s,
căng thẳng
(c)) == -1)
errExit(
"ghi \"%s\" vào tệp mô tả(%d) không thành công"
, s, fd);
trở lại
0;
}
xyz@ubuntu:~/unp_practice/lib$ g++ test.cc -std=c++11
xyz@ubuntu:~/unp_practice/lib$ ./a.out
viết
"Xin chào thế giới!"
đến file descriptor(-1) không thành công: Mô tả file không hợp lệ
|
Tóm tắt.
Trên đây là toàn bộ nội dung bài viết mong rằng nội dung bài viết có giá trị tham khảo nhất định cho quá trình học tập, làm việc của mọi người.
Link gốc: https://www.jianshu.com/p/548e43f4ced8.
Cuối cùng, bài viết này về việc tạo mã ví dụ chuỗi tiêu chuẩn được định dạng bằng C++ kết thúc ở đây. Nếu bạn muốn biết thêm về mã ví dụ chuỗi tiêu chuẩn được định dạng bằng C++, vui lòng tìm kiếm các bài viết CFSDN hoặc tiếp tục duyệt các bài viết liên quan, tôi hy vọng bạn sẽ ủng hộ blog của tôi trong phần này. tương lai! .
Tôi là một lập trình viên xuất sắc, rất giỏi!