#include <iostream>
#include <string>
#include <set>
#include <sstream>
#include <iterator>
#include <cctype>
#include <algorithm>
using namespace std;

bool isWordSeparator(char & c) {
    return c == ' ' || c == '-' || c == '\n' || c == '?' || c == '.' || c == ','
    || c == '?' || c == '!' || c == ':' || c == ';';
}


int main()
{
    string s = "ab\nAb!aB?AB:ab.AB;ab\nAB\nZZZZ zzzz Zzzz\nzzzz";

    transform(s.begin(),s.end(),s.begin(),
        [](char c)->char { if(isWordSeparator(c)) return ' '; return tolower(c); });

    istringstream iss(s);

    //This will create a set of lowercase tokens, leaving the duplicates out:
    set<string> words((istream_iterator<string>(iss)), istream_iterator<string>());

    cout << "Number of Words: " << words.size()  << endl;

    return 0;
}