Cách thêm dấu phẩy giữa mỗi nghìn trong số nguyên (digit grouping)

Ví dụ: 1000000 -> 1,000,000


Ý tưởng của em như trên nhưng code không chạy ạ.
Anh chị giúp em giải với.

C++ có numpunct nè em :V https://en.cppreference.com/w/cpp/locale/numpunct/grouping

#include <iostream>
#include <locale>
 
struct g3 : std::numpunct<char> {
    char do_thousands_sep()   const { return '.';  } // separate with .
    std::string do_grouping() const { return "\3"; } // groups of 3 digit
};
 
int main() {
    std::cout.imbue(std::locale(std::cout.getloc(), new g3));
    
    std::cout << 1 << '\n';
    std::cout << 12 << '\n';
    std::cout << 123 << '\n';
    std::cout << 1234 << '\n';
    std::cout << 12345 << '\n';
    std::cout << 123456 << '\n';
    std::cout << 1234567 << '\n';
    std::cout << 12345678 << '\n';
    std::cout << 123456789 << '\n';
    std::cout << 1234567890 << '\n';
}

in ra

1
12
123
1.234
12.345
123.456
1.234.567
12.345.678
123.456.789
1.234.567.890
7 Likes

anh ơi anh giải thích giúp em từng dòng được không ạ

có vài 3 dòng người ta viết sẵn em xài thôi :joy:

ostream trong C++ có kèm theo 1 đối tượng locale :V Đối tượng này được ostream dùng để in ra định dạng (format) nhiều kiểu dữ liệu. Trong locale lại có đối tượng numpunct dùng để format số nguyên :V Class numpunct này cho phép đa hình, nghĩa là có thể tạo định dạng mới cho số nguyên thông qua kế thừa class numpunct và nạp chồng (override) các toán tử định dạng số nguyên trong đó:

struct g3 : std::numpunct<char> {
    //...
}

numpunct bản chất là template :V vì cout in ra char nên xài numpunct<char> ở đây

sau đó override 2 hàm do_thousands_sepdo_grouping trong numpunct là được:

char do_thousands_sep()   const { return '.';  }

do_thousands_sep trả về char là ký tự ngăn cách phần nghìn. Mặc định là dấy phẩy , ở đây override lại thành dấu chấm .

std::string do_grouping() const { return "\3"; }

do_grouping trả về kiểu string nhưng đây ko phải chuỗi chứa ký tự bình thường mà là chuỗi chứa các giá trị nhị phân :V Do nhiều thứ tiếng loài người kì lạ ko chỉ có nhóm 2, nhóm 3, nhóm 4, mà còn có nhóm 2 rồi nhóm 3 :V :V :V v.v… nên phải trả về nhiều giá trị chứ ko phải chỉ có 1 giá trị được :V Ở đây tiếng Việt đơn giản :V chỉ cần trả về 1 số 3 là 3 chữ số cho mỗi nghìn là được, trả về chuỗi "\3" là xong. Ký tự '\3' có giá trị 3, khác với ký tự '3' có giá trị là 51.

override xong g3 (đặt tên tạm là viết tắt của group 3 :V) từ numpunct thì ta phải gán đối tượng này vào cho locale của cout. Gán locale cho cout bằng hàm std::cout.imbue(...). Tạo locale mới bằng cách gọi constructor (ctor) của locale: std::locale(...). Trong các ctor của locale có ctor số (7) là tạo locale mới từ locale sẵn có, chỉ thay 1 facet, ở đây là facet numpunct

std::locale(std::cout.getloc(), new g3)

new g3 có thể được hiểu là con trỏ tới numpunct, mà con trỏ tới numpunct có thể hiểu là con trỏ tới Facet :V Cái này gọi là đa hình :V

xong rồi imbue nó vào cout là được:

std::cout.imbue(std::locale(std::cout.getloc(), new g3));

làm xong có thể sử dụng cout bình thường, nó tự động format số nguyên theo định nghĩa mà ta định nghĩa trong g3

7 Likes

nói chung em nhớ numpunct rồi google “cppref numpunct” là ra hoặc gg “cppref do thousand sep” cũng ra :V Đọc code ví dụ rồi copy paste chỉnh sửa tí là ok :innocent:

7 Likes

ui thank anh chu đáo quá =) em đọc cũng câu được câu mất nên save tạm đợi thêm vài năm nữa mới thấm được anh ạ :upside_down_face: chạy ngon lành rồi anh :laughing:

83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?