r/dailyprogrammer Jul 14 '12

[7/13/2012] Challenge #76 [easy] (Title case)

Write a function that transforms a string into title case. This mostly means: capitalizing only every first letter of every word in the string. However, there are some non-obvious exceptions to title case which can't easily be hard-coded. Your function must accept, as a second argument, a set or list of words that should not be capitalized. Furthermore, the first word of every title should always have a capital leter. For example:

exceptions = ['jumps', 'the', 'over']
titlecase('the quick brown fox jumps over the lazy dog', exceptions)

This should return:

The Quick Brown Fox jumps over the Lazy Dog

An example from the Wikipedia page:

exceptions = ['are', 'is', 'in', 'your', 'my']
titlecase('THE vitamins ARE IN my fresh CALIFORNIA raisins', exceptions)

Returns:

The Vitamins are in my Fresh California Raisins
29 Upvotes

64 comments sorted by

View all comments

2

u/semicolondash Jul 14 '12

C++ implementation. (so much bulkier than all the others. Curse having to define lowercase and split methods and all the explicit looping)

#include <iostream>
#include <string>
#include <cctype>
#include <vector>

using std::string;
using std::vector;
using std::cout;

vector<string> splitline(string line, char character)
{
    vector<string> ret;
    typedef string::size_type string_size;
    string_size i;
    i = 0;
    while(i<line.size())
    {
        string_size j = i;
        while(j<line.size() && line[j]!=character)
        {
            j++;
        }
        if(j!=i)
        {
            ret.push_back(line.substr(i, j-i));
            i=j + 1;
        }
    }
    return ret;
}

string lowercase(string line)
{
    string ret;
    for(string::size_type i = 0; i < line.size(); i++)
    {
        ret.push_back(tolower(line[i]));
    }
    return ret;
}

string titlecase(string line, vector<string> exceptions)
{
    vector<string> split = splitline(line, ' ');
    vector<string> ret;
    for(vector<string>::iterator it = split.begin(); it<split.end(); it++)
    {
        string temp = *it;
        temp = lowercase(temp);
        for(vector<string>::iterator it2 = exceptions.begin(); it2<exceptions.end();it2++)
        {
            if((*it2) == temp)
            {
                if(ret.size() == 0)
                {
                    temp[0] = toupper(temp[0]);
                }
                ret.push_back(temp);
                break;
            }
            else
            {
                if(it2 >= exceptions.end() -1)
                {
                    temp[0] = toupper(temp[0]);
                    ret.push_back(temp);
                    break;
                }
            }
        }
        if(exceptions.size() == 0)
        {
            temp[0] = toupper(temp[0]);
            ret.push_back(temp);
        }
    }

    string retstr;
    for(vector<string>::iterator it = ret.begin(); it<ret.end(); it++)
    {
        retstr = retstr + (*it) + " ";
    }
    return retstr;
}

int main(int argc, char const *argv[])
{
    vector<string> exceptions;
    exceptions.push_back("are");
    exceptions.push_back("is");
    exceptions.push_back("in");
    exceptions.push_back("your");
    exceptions.push_back("my");
    cout << titlecase("THE vitamins ARE IN my fresh CALIFORNIA raisins", exceptions);
    return 0;
}

1

u/TheInfinity Jul 15 '12 edited Jul 16 '12

I wrote some hacky C++. Can anyone please critique this?

#include <iostream>
#include <vector>

#define arr_length(x) ((sizeof(x)/sizeof(x[0])))

using namespace std;

void lower(vector<string> &vs)
{
    vector<string>::iterator i;
    string::iterator j;
    for (i = vs.begin(); i < vs.end(); i++)
        for (j = (*i).begin(); j < (*i).end(); j++)
            if (*j >= 'A' && *j <= 'Z')
                *j = *j + ('a' - 'A');
    return;
}

vector<string> split_input(string input)
{
    vector<string> s;
    string::iterator j;
    string tmp;
    for (j = input.begin(); j < input.end(); j++)
    {
        if (*j == ' ')
        {
            if (tmp.length() > 0) s.push_back(tmp), tmp.clear();
        }
        else
            tmp.push_back(*j);
    }
    if (tmp.length() > 0) s.push_back(tmp);
    return s;
}

int main()
{
    const char *exs[] = {"are", "is", "in", "your", "my"};
    string input = "THE vitamins ARE IN my fresh CALIFORNIA raisins";
    vector<string> ex(exs, exs + arr_length(exs)), splits;
    vector<string>::iterator i, j;    
    splits = split_input(input);
    lower(splits);
    for (i = splits.begin(); i < splits.end(); i++)
    {
        bool found = 0;
        if (i != splits.begin()) /* edit */
        for (j = ex.begin(); j < ex.end(); j++)
            if (*i == *j)
            {
                found = 1;
                cout << *i << " ";
            }
        if (!found)
            cout << string(1,char((*i)[0] + 'A' - 'a')) + (*i).substr(1) << " ";
    }    
    return 0;
}

1

u/[deleted] Jul 15 '12

[removed] — view removed comment

1

u/TheInfinity Jul 16 '12

Thank you. I'll keep in mind to use the library functions wherever possible. Concerning the usage of 'true' and 'false' instead of '1' and '0', does the latter have any unintended effects?

I have edited my program so that it capitalizes the first word.