Posts Tagged ‘ string ’

Formatting and Styling Strings (C#)

We’ve discussed different ways to format a string using printf for C++ and string.format for Java/Android and since I’ve been working with C# recently I would add that to the blog as well.

In C#, it’s just like Java/Android: use string.Format(). Instead of dollar signs, you would use curly brackets with the parameter number. What’s nice is that you don’t really need to worry about the type. For example:

int foo = 9000;
string bar = "sparta";

string fubar = string.Format("This is {0}! It is over {1}!", bar, foo);

Would result with:

This is sparta! It is over 9000!"

See how I didn’t need to tell it {0} was a string and {1} was an integer? You can also add the format inside the curly bracket if you wish such as:

{index,length:formatString}

Where index is the index of the value to use; length is the amount of spaces you want this variable to take up; and formatString is a standard or custom string that can be used to do more formatting (such as setting up a date in US or EU format).

As usual, if you’d like to know more about the details, visit MSDN for more reading.

Advertisements

Writing and getting variables from Windows registry

MFC makes it easy to use the Windows Registry to store your application’s settings and variables. This allows your application to retain last used options, recent files, preferences, colors, fields, whatever. I’m assuming that you can use Visual Studio’s new project wizard to make a new MFC application/project.

I am using Visual Studio 2008 SP1 on Windows Vista 32-bit as of the writing of this article.

In the main cpp file that is generated, find the InitInstance() function. In this function, there should be a function call to SetRegistryKey. This function takes in a LPCTSTR (which is a long pointer to string) and you can just give it any string (Microsoft recommends using the company name here). I would use it like this:

SetRegistryKey(_T("My Fookin Company"));

The “_T()” part is just a macro that converts the string to a LPCTSTR. This line is all you need to set your program to use the registry. If it isn’t in InitInstance(), then just add it.

To save information to the registry, you would use the following code:

// get the current application object
CWinApp* pApp = AfxGetApp();

// This is the string I want to save
CString engrName = "Alex";
int age = 24;

// "ArbitrarySectionName" is the collection of information to store (if you have multiple sections in your application such as "userProfile" and "userSettings" then you would use those different names)
// _T("engrName") is a variable in the registry. you create this here so you can name it "foobar" for all it cares
// just remember what you named it so you can get it later
// engrName (the last parameter) is what you're saving (in this case, it is the string "Alex")
pApp->WriteProfileString(_T("ArbitrarySectionName"), _T("engrName"), engrName );

// let's just save an integer for the hell of it
pApp->WriteProfileInt(_T("ArbitrarySectionName"), _T("engrAge"), age);

// not using pointer anymore
pApp = NULL;

To get information from the registry, you would have needed to save information there in the first place. If there is nothing there, you would get blank information. To get the information from the registry you would use the following code to get it:

// get the current application object
CWinApp* pApp = AfxGetApp();

// get string from registry and assign to a string
// GetProfileString returns a CString object
// GetProfileInt returns an integer
// "ArbitrarySectionName" is where the collection of information is stored (you set this on save)
// "engrName" and "engrAge" are the variables in the section "ArbitrarySectionName" where you saved single pieces of data
CString strVar = pApp->GetProfileString(_T("ArbitrarySectionName"), _T("engrName") ) );
int intVar = pApp->GetProfileInt(_T("ArbitrarySectionName"), _T("engrAge") ) );

// not using pointer anymore
pApp = NULL;

You can use both pieces of code anywhere in your MFC classes. Just note there are only functions for integers and strings. None for decimal numbers, unfortunately. For more information, here are some links to MSDN:

SetRegistryKey()
WriteProfileInt()
GetProfileInt()
WriteProfileString()
GetProfileString()
Article that I used to figure out how to use the registry

Formatting and Styling Strings (C/C++)

So, talking about formatting and styling strings for Java/Android has got me thinking about formatting and styling strings for C/C++. For C/C++, we use printf and sprintf. Both printf and sprintf work exactly the same except sprintf puts the output to a character array and printf puts the output to standard output (such as the console/terminal).

If you just want to put a line out to standard output, you’d write something like this:

printf("Hello World!\n");

If you want to output strings and numbers, you’d use it like this:

float freqMHz = 100.2578;
printf("%-30s: %5.2f MHz\n", "Frequency", freqMHz);

The previous example is a bit more advanced, but that’s probably as advanced as it gets. %-30s means the first parameter is a string (the “s”) and we want to allot 30 spaces for the string and left align it (the “-“). The %5.2f means the second parameter is a float and we want to format it such that we want 5 digits for the integer part with a 2 digit precision for the decimal part. The string sent to standard output would be as follows:

Frequency:                    100.26 MHz

Note that the float gets rounded up when it is formatted. For sprintf, the syntax is the same, except we add a character array to the parameters. The character array is where we would save the final string. For example, the following code will output the exact same thing as the above example:

char* outputStr = new char[1024];
sprintf(outputStr, "%-30s: %5.2f MHz\n", "Frequency", freqMHz);
printf(outputStr);

The cool thing about printf and sprintf is that you can add as many parameters as you want to the formatted string. The useful thing about printf and sprintf is that you can mix and match data types (like in the previous examples) without having to do typecasting or using (with cout) to get it to look nice. You can even format numbers to hexadecimal or scientific notation! Pretty slick, right?

Also, remember to add a newline character (“\n”) to the end of the string. It will run the next printf on the same line as the previous printf if you don’t.

Anyways, for all the different flags you can use to format printf and sprintf, check out the documentation at cplusplus.com.

Formatting and Styling Strings (Java/Android)

So, let’s say you’re reading the Android document on formatting and styling strings and come across the line

Hello, %1$s! You have %2$d new messages.

The document explains that %1$s and %2$d are a string and decimal value, respectively. The next chunk of code is

String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);

Now, how does this relate? Well, the 1$ and 2$ means first and second parameter, respectively. So in this case %1$s is replaced with the variable username and %2$d is replaced with mailCount.

Why should you construct strings this way instead of constructing a string with the plus sign? Well, either way is valid, but this is just the “old” way of constructing strings. There was a time where using the plus sign to construct strings required converting decimal numbers to a string or else the compiler would complain. It was an obnoxious intermediate step. With Java though, the plus sign is smart enough to change the datatype of a decimal to a string if the rest of the line contains strings. To make a string (that contains a number) to a decimal, just add “+ 0” to the end and Java will take care of it. Pretty slick, right?

Absolute paths for input/output

Just a hint based on my own negligence: when using absolute paths to files using fstream or fopen, you do not need to wrap the string with escaped double quotes ( \” ). This is based on the mistaken assumption that if there are spaces you must wrap the path in double quotes since the Windows command prompt doesn’t like spaces in the file path.

You DO need to use the escaped backslash ( \\ ) between folders though.

Instead of this:

ofstream out;
out.open( "\"C:\\Users\\Alex\\Documents\\Visual Studio 2008\\file2.txt\"");

Use this:

ofstream out;
out.open( "C:\\Users\\Alex\\Documents\\Visual Studio 2008\\file2.txt");

Reference:
Stack Overflow

String Tokenizer

A tokenizer basically splits a string by the white space in the string. For example, the string “70 brown foxes jumps 20 feet” would be split into the terms “70”, “brown”, “foxes”, “jumps”, “20”, and “feet”. This way you can process the words* individually.

*Technically they’re called tokens, but I call them words because it’s easier to relate it to English. The terms are interchangeable in this post, but “word” has a different meaning in programming.

I came across an elegant string tokenizer at Stack Overflow:
http://stackoverflow.com/questions/236129/how-to-split-a-string

Basically add these to the header:

#include <iostream>
#include <sstream> // needed to convert string into an input stream
#include <string> // only if you're using visual studio
#include <vector> // used to store the words of the string
#include <iterator>
using namespace std;

I don’t know why #include <algorithm> is needed as I didn’t include it and it works fine (your mileage will vary). #include <iterator> is needed to move around the stream.

I put the tokenizer into a function so it can be reused. It takes in the string to parse and the container to hold the parsed tokens. The vector container is passed by reference so it can be returned.

void tokenizer(string line, vector<string>& tokens){
	// gets all the words out of a string. a word is something separated by spaces

	// convert the string into a stream which separates the words by the whitespace
	istringstream iss(line);

	// reads the stream, puts word in a vector, repeats until stream is empty
	copy(istream_iterator<string>(iss),
		istream_iterator<string>(),
		back_inserter< vector >(tokens));
}

Then to use the tokenizer, you would need to create the vector to hold the words and then send it with the string to be parsed.

string line = "70 brown foxes jumps 20 feet"
vector<string> tokens;
tokenizer(line, tokens);

Remember how C++ vectors work? Now you can access the words like so:

tokens[index]

Awesome, right? Wish I knew about this in college!