String stream

stringstream untuk parsing dan konversi angka.

Daftar isi

std::stringstream adalah stream yang sumber maupun tujuannya berupa std::string di memori, bukan berkas atau layar. Topik ini membahas std::istringstream untuk membaca dan mengurai string, std::ostringstream untuk menyusun string dari beberapa nilai, serta fungsi konversi angka seperti std::stoi dan std::to_string yang sering menyanding dengannya. Seluruh contoh bekerja tanpa berkas eksternal, sehingga mudah dicoba langsung.

Membaca string dengan istringstream#

std::istringstream memperlakukan string sebagai aliran data, sehingga operator >> dan std::getline bekerja di atasnya persis seperti di atas berkas. Keunggulan utamanya adalah kemudahan uji coba, karena data masukan dapat ditulis langsung di dalam kode. Operator >> mengonversi potongan teks sesuai tipe variabel sasarannya, dan perulangan di atasnya berhenti ketika data habis.

cpp konversi-angka.cpp
#include <iostream>
#include <sstream>
#include <string>

int main() {
    // menjumlahkan angka yang tersimpan sebagai satu string
    std::istringstream masuk("10 24 100");
    int total = 0;
    int nilai = 0;
    while (masuk >> nilai) {
        total += nilai;
    }
    std::cout << "total: " << total << "\n";

    // mengambil angka dari depan teks dengan std::stoi
    std::string teks = "42cm";
    std::size_t sisa = 0;
    int panjang = std::stoi(teks, &sisa);
    std::cout << "angka: " << panjang << ", satuan: " << teks.substr(sisa) << "\n";

    // menyusun string dari beberapa nilai dengan ostringstream
    std::ostringstream keluar;
    keluar << "Suhu rata-rata: " << 23.65 << " derajat";
    std::cout << keluar.str() << "\n";
    return 0;
}
text Keluaran
total: 134
angka: 42, satuan: cm
Suhu rata-rata: 23.65 derajat

Bagian kedua memperlihatkan std::stoi, yang mengubah awal string menjadi int dan melaporkan posisi berhentinya melalui argumen kedua bertipe std::size_t*. Informasi itu dipakai untuk mengambil satuan yang tersisa, yaitu cm, dengan substr. Bagian ketiga memakai std::ostringstream untuk menyusun kalimat laporan dari angka dan teks sekaligus, kemudian .str() mengambil hasilnya sebagai std::string.

Perulangan while (masuk >> nilai) bekerja karena operator >> melewati spasi yang memisahkan token, lalu mengonversi potongan berikutnya sesuai tipe variabel sasarannya. Setiap ekstraksi melanjutkan posisi baca dari titik berhenti sebelumnya, sehingga ketiga angka terkumpul dari satu aliran yang sama. Ketika data habis, ekstraksi gagal dan stream menjadi bernilai false, yang mengakhiri perulangan tanpa penghitung eksplisit. Mekanisme inilah alasan string stream disukai untuk pengujian, karena penguraian yang identik dengan penguraian berkas dapat dicoba menggunakan data yang tertulis di dalam kode.

Konversi angka tanpa exception#

std::stoi melempar exception ketika konversinya gagal, sedangkan dua mekanisme lain menandai kegagalan tanpa melempar apa pun. std::istringstream menandainya lewat bit keadaan yang dibahas pada topik keadaan stream, sedangkan std::from_chars dari C++17 melaporkan hasilnya lewat struct hasil kembalian. std::from_chars mengonversi deret karakter menjadi angka tanpa alokasi memori dan tanpa bergantung pada pengaturan locale, sehingga cocok untuk penguraian berfrekuensi tinggi.

cpp konversi-aman.cpp
#include <charconv>
#include <iostream>
#include <string_view>

void coba(std::string_view teks) {
    int nilai = 0;
    auto hasil = std::from_chars(teks.data(), teks.data() + teks.size(), nilai);
    if (hasil.ec == std::errc{}) {
        std::cout << "'" << teks << "' -> " << nilai
                  << ", sisa " << teks.substr(hasil.ptr - teks.data()) << "\n";
    } else if (hasil.ec == std::errc::result_out_of_range) {
        std::cout << "'" << teks << "' -> melebihi jangkauan int\n";
    } else {
        std::cout << "'" << teks << "' -> gagal dikonversi\n";
    }
}

int main() {
    coba("24kg");
    coba("berat");
    coba("99999999999");
    return 0;
}
text Keluaran
'24kg' -> 24, sisa kg
'berat' -> gagal dikonversi
'99999999999' -> melebihi jangkauan int

Hasil konversi diperiksa lewat hasil.ec, yang bernilai std::errc{} apabila berhasil, std::errc::result_out_of_range apabila angkanya melebihi jangkauan tipe sasaran, dan std::errc::invalid_argument apabila tidak ada angka di awal teks. Anggota hasil.ptr menunjuk karakter pertama yang tidak ikut dikonversi, sehingga perannya sama dengan parameter pos pada std::stoi. Ketiga cara konversi ini saling melengkapi, yaitu std::stoi untuk kode biasa yang tidak keberatan dengan exception, std::istringstream untuk penguraian bertahap, dan std::from_chars untuk jalur yang tidak boleh melempar.

Membagi baris menjadi kolom#

Banyak format data sederhana memisahkan kolom dengan satu karakter tertentu, misalnya titik koma. std::getline menerima argumen ketiga sebagai pemisah kustom sehingga baris dapat dipecah tanpa menulis pengurai sendiri. Hasil setiap potongan kemudian dikonversi dengan std::stoi apabila kolomnya berupa angka.

cpp urai-baris.cpp
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

int main() {
    const std::string baris = "Citra;80;90;85";

    std::istringstream masuk(baris);
    std::string nama;
    std::getline(masuk, nama, ';');

    std::vector<int> nilai;
    std::string kolom;
    while (std::getline(masuk, kolom, ';')) {
        nilai.push_back(std::stoi(kolom));
    }

    int total = 0;
    for (int n : nilai) {
        total += n;
    }
    std::cout << nama << ": " << nilai.size() << " nilai, "
              << "rata-rata " << total / static_cast<double>(nilai.size()) << "\n";
    return 0;
}
text Keluaran
Citra: 3 nilai, rata-rata 85

Potongan pertama diambil untuk nama, sedangkan perulangan while mengambil tiga kolom angka berikutnya. Pemanggilan std::getline berikutnya sesudah itu menemukan akhir data dan menggagalkan perulangan, sehingga vektor nilai tepat berjumlah tiga elemen tanpa potongan kosong. Pola ini cocok untuk data dengan jumlah kolom yang tetap, sedangkan data yang lebih bebas sebaiknya diperiksa jumlah kolomnya terlebih dahulu sebelum nilai-nilainya dipakai.

Menyusun string dengan ostringstream#

std::ostringstream merupakan kebalikan arahnya, yaitu menampung keluaran format ke dalam string. Semua operator << dan manipulator iostream tetap berlaku, sehingga angka dan teks dapat digabung tanpa konversi manual. Pendekatan ini menjadi cara idiomatik untuk membangun pesan error, laporan, atau baris data terstruktur sebelum dikirim ke tujuan akhirnya.

cpp susun-laporan.cpp
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

int main() {
    std::vector<std::string> nama = {"Ali", "Budi", "Citra"};
    std::vector<double> rataRata = {78.5, 84.0, 91.25};

    std::ostringstream laporan;
    for (std::size_t i = 0; i < nama.size(); ++i) {
        laporan << "- " << nama[i] << ": " << rataRata[i] << "\n";
    }

    std::cout << laporan.str();
    return 0;
}
text Keluaran
- Ali: 78.5
- Budi: 84
- Citra: 91.25

Seluruh baris laporan tersusun di memori terlebih dahulu, kemudian dicetak sekali lewat .str(). Apabila laporan perlu ditulis ke berkas, string yang sama dapat dikirim ke std::ofstream tanpa mengubah susunannya. Nilai yang dikembalikan .str() berupa salinan, sehingga penambahan isi stream sesudahnya tidak mengubah string yang sudah diambil. Tampilan double pada contoh mengikuti pengaturan bawaan iostream, dan pengaturan presisinya dibahas lebih lanjut pada topik pemformatan.

Kesalahan umum#

Kekeliruan berikut paling sering muncul saat string stream mulai dipakai.

  • Memakai std::stoi pada masukan yang mungkin tidak valid. Fungsi ini melempar exception std::invalid_argument apabila tidak ada angka di awal string. Perbaikannya menggunakan std::istringstream dengan pemeriksaan kondisi, atau menangkap exception tersebut.
  • Mengira std::stoi menandai konversi yang hanya berhasil sebagian. Teks 12abc dikonversi menjadi 12 tanpa exception karena fungsi itu berhenti pada karakter pertama yang bukan angka. Perbaikannya memeriksa parameter pos, atau memakai std::from_chars yang melaporkan posisi berhentinya secara bawaan.
  • Mengira operator >> membaca sepanjang baris. Operator ini berhenti pada spasi sehingga teks yang mengandung spasi terpotong. Perbaikannya membaca baris dengan std::getline terlebih dahulu.
  • Memakai ulang stream yang telah habis atau gagal tanpa pemulihan. std::istringstream yang mencapai akhir tetap berada di sana hingga keadaannya dipulihkan. Perbaikannya memanggil clear() untuk menghapus bit error, lalu mengganti isinya dengan str().
  • Lupa memanggil .str(). Isi std::ostringstream tidak dapat dipakai sebagai std::string tanpa fungsi itu. Perbaikannya mengambil isinya lewat .str() sebelum dicetak atau disimpan.

Ringkasan#

  • std::istringstream membaca string sebagaimana std::ifstream membaca berkas, lengkap dengan konversi melalui operator >>.
  • std::getline dengan argumen pemisah memecah baris menjadi kolom, dan std::stoi mengonversi potongan angka sekaligus melaporkan posisi berhentinya.
  • std::ostringstream menyusun string dari beberapa nilai dengan <<, lalu .str() mengambil hasilnya.
  • std::to_string praktis untuk satu nilai, tetapi formatnya tetap dan tidak dapat diatur.

Referensi#