c++stdvectorstdmapdecoder

How do I use a std::map to change a vector of strings into another vector of characters?


I am am trying to make a decoder where you input the words comprising the NATO phonetic alphabet, and have it eventually spit out the translated sentences, only the actual "switcher" is not made.

#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <map>
#include <sstream>
using namespace std;

int main() {
    map<char, string> NATOMap = { {' ',"-"}, {'a', "alfa"}, {'b', "bravo"}, {'c', "charlie"}, {'d', "delta"}, {'e', "echo"}, {'f', "foxtrot"}, {'g',"golf"}, {'h',"hotel"}, {'i',"india"}, {'j', "juliett"}, {'k', "kilo"}, {'l', "lima"}, {'m',"mike"}, {'n', "november"}, {'o', "oscar"}, {'p', "papa"}, {'q',"quebec"}, {'r', "romeo"}, {'s',"sierra"}, {'t', "tango"}, {'u', "uniform"}, {'v',"victor"}, {'w',"whiskey"}, {'x',"xray"}, {'y',"yankee"}, {'z', "zulu"} };
    
    //this input comes from a file, placed here for easier testing
    string Dinpustring = "hotel echo lima lima oscar - whiskey oscar romeo lima delta";
    
    //split text
    string temp;
    stringstream ss(Dinpustring);
    vector<string> inputDxt;
    while (getline(ss, temp, ' ')) {
        inputDxt.push_back(temp);
    }
    //spit out text (testing purpouses)
    cout << "text get:\n";
    for (int i = 0; i < inputDxt.size(); i++) {
        cout << inputDxt[i] << endl;
    }
    
    //switcher(probably contains loops)??
    
    
    //not necessary for here, only to show where its supposed to end up
        fstream Doutfile3;
    Doutfile3.open("Dencoded.txt", ios::out, ios::trunc);
    if (outfile3.is_open()) {
        outfile3 << outputDxt;
    }
    outfile3.close();
    return 0;
}

I have not previously worked with maps before, I barely got acquainted with vectors somewhat, so I have no idea where to at least start from; the rest of the code I have tested and know to work.


Solution

  • Your map is the wrong way around. If your input is made of NATO words, it should be map<string, char>. The first template argument is the key, i.e. what you look up, and the second argument is the value, i.e. the value associated with the looked-up key.

    Since order doesn't matter here, you could use unordered_map just as well as map.

    // make this global
    const std::unordered_map<std::string, char> NATOMap = {
        {"-", ' '}, {"alfa", 'a'}, {"bravo", 'b'}, /* ... */
    };
    

    Also, you should use ss >> temp, not getline(ss, temp, ' ') to read each word. getline does not handle multiple consecutive spaces nicely and gives you empty strings in such cases.

    Then:

    // C++11
    std::string decode(const std::vector<std::string>& words) {
        std::string result;
        for (const auto& word : words) {
            auto it = NATOmap.find(word);
            // If the word wasn't found, we push a '?' character.
            // You could also throw an exception in this case.
            result.push_back(it == NATOmap.end() ? '?' : it->second);
        }
        return result;
    }
    
    // C++23
    std::string decode(std::span<const std::string> words) {
        return {std::from_range, words | std::views::transform([](const auto& word) {
            auto it = NATOmap.find(word);
            return it == NATOmap.end() ? '?' : it->second;
        })};
    }
    
    std::vector<std::string> inputDxt; // vector containing all input words
    // fill inputDxt ...
    std::cout << decode(inputDxt) << '\n';