![]() | Monkeys at Keyboards: APE Antics © Michael James Heron and Pauline Belford | ||||
| Topic: Java Programming Level: 1 Version: alpha | |||||
10 - Stringing Your Words Together | |||||
| Previous | Table of Contents | Next |
| Forum |
| Chapter Objectives |
By the end of this chapter, the reader will be able to:
|
In days gone by, there didn't exist such a thing as a 'String' to programming languages like C. They treated Strings as something much less intuitive - contextually linked lists of single characters. This made it quite difficult to work with strings of text, which was unfortunate - strings are one of the most useful and common types of data that programmers have to deal with. Those Bad Old Days are gone now though, and as Java programmers we have access to a type of data called, unsurprisingly, the String. This data type is used for storing and manipulating strings of alphanumeric characters.
The String data type is slightly different to the data types you have used before -it's more powerful and complex than ints and doubles. We have used the String data type before, but in this chapter we're going to look at some of the things that can be done with the String datatype. Strings are immensely versatile and will provide a very useful tool in your arsenal of weapons, so let's get on with the main content.
We create a String in the standard way:
And we assign values in the usual manner:
This much is familiar - but much like the Pacman game, Strings have methods to go with them, and these methods let us perform useful functions on the data. Say for example we wanted to turn a string into an upper-case version of itself:
It's really that simple - myString would then contain an uppercase version of the text it originally contained. We can turn a string entirely lower-case too by using the toLowerCase method:
Not bad, eh? But that's only the beginning - we have so much more we can do with Strings, and we'll be using in the course of this chapter to tell Pacman what to do. So, a String contains some data (the text you give it), and some methods for acting on that data. This sets them aside from ints and doubles, and so we categories data types into two categories:
Java treats these two kinds of data differently when it sees them, but we'll talk about that later - for now, just take on board the fact we are working with a complex data type.
If you've spent any time in the past few chapters trying to work with Strings, you may have noticed something quite strange - if you use == or != to try and determine if one string equals another, it doesn't always work. This is because of what is hinted above - Java treats complex data types differently for primitive data types. A String is a complex data type, and so when you try to use one of the equivalence operators on the String, what Java does is check to see if the memory location of one string is equal to the memory location of another string. This will only be the case if the two strings are the same string - but that's not usually what you are trying to do. What you want is to know if String A has the same contents as String B, and the == operator will not do that for you. We'll discuss this in more depth when we talk about reference and value data-types later in the book. Instead, we must use the equivalence methods provided by the String data-type to do our comparisons - this is the only way to ensure that our code always works. The first of these methods is equals(), and takes a single String parameter which is the String to check against:
Equals is a case sensitive comparison, which means that the if statement above will evaluate to true only if myString contains "bing!". It won't work if it contains "Bing!", "BING!", or any combination of alternate casings. This can be quite unhelpful, so Java provides us with a second equivalence method. It works exactly the same way, it just ignores the case of letters:
This method will cause the if statement to evaluate as true if myString contains "Bing!", "bing!", "BinG" or any combination. This is much more convenient!
Since Strings are alphanumeric in nature, we also get some zany results if we try and perform mathematical operators on them as you can image. What is "bing" * "bing", for example? In Java's opinion, it is an error and it will refuse to countenance such nonsense, and you will be similarly rebuffed if you try and divide or subtract strings. However, Java is happy for you to add Strings together - all it will do is take the second string and add it onto the end of the first string. This is a process called concatenation, and in the context of adding strings together the + symbol is properly known as the concatenation operator. Let's look at example of this:
This gives us the following output when we run the program:
It just takes the second String and adds it onto the end of the first string. But it's also quite clever, because it will also do 'on the fly' conversions of other data types into Strings as it does so. That may sound complex, so let me explain. Let's say you wanted to store a number as a String. How do you do it? The first instinct may be to do something like this:
Alas, no. Java will complain bitterly at this, since an int is not a String, how many times does it have to tell you? But we can fool Java - Java will automatically convert any other data type into a String if you try to add it to another String - first it converts the other data types and then attempts to concatenate them in the way you request:
In this case, Java thinks to itself 'Ah-ha, I'm being asked to add these two together, but number isn't a string. I'll make it into a String, which will solve the problem'. This then becomes, in Java's mind:
This then becomes a string containing 100 concatenated onto an empty string, giving us "100". Very handy! This kind of implicit data conversion allows you to turn any kind of data type into a string ready for making use of. We can concatenate as many strings as we like:
And we can also implicitly convert any number of variables as we do so. This will become more and more powerful the further you progress through this book.
So, what methods do strings have to Excite and Entice us? As it happens, they have lots and lots of them! Some of these are too complex for us to go into, but we'll look at some of the simpler ones here and why they are important to us. We have a trim() method, which removes any white-space from the beginning and end of a string - very useful for ensuring that you don't need to waste time checking for spaces where they shouldn't be. We use this the same way as we do toUpperCase or toLowerCase:
This would change a string such as:
Into:
We'll see that this is a very handy method later in the chapter when we start trying to communicate with Pacman. Another very useful method we'll soon see in action is length(), and this gives us how many characters there are in a string. This gets returned as a whole number:
These methods will serve as the basis for what we are going to do in this chapter. We will introduce further methods during the text of the book as they are appropriate.
Wouldn't it be cool if we didn't have to write the program for Pacman for each map he's on? We could load up a map, look at it, and tell exactly how it should be solved. It's fairly hard work making Pacman work out how to navigate a map, after all - why can't we control him ourselves like in the arcade game? Well, there's no reason why not - in fact, why don't we make it so that we can issue him commands ourselves? We don't know how to make him respond to a keyboard or mouse (and won't for a long time), but we do know how to request information from the user - we saw that in chapter three - we use the getTextFromUser method. Why not ask the user for instructions? By Jingo, that's a great idea - let's do that! We write the initial shell of the program, prompting the user for instructions:
Hrm. Now what? We run the program and we get asked for instructions - but nothing happens!
That's because we have the instructions from the user, but we're not doing anything with it. We need a way to turn the String we have in the instructions variable into an actual command to Pacman.
Extracting such information from a string is a process known as parsing. We must parse our string to extract the juicy, tasty orders.
How do we do that? Well, that's the first problem - how do we want the user to submit orders? What if the user write 'Turn left, you yellow git'? How do we tell from that what Pacman is supposed to do? We can read it and understand, but how do we get pacman to understand? The simple answer is - we don't. It's well beyond us to write a program that will analyse any text given for meaning and instruction, purely because of the richness of language when expressing these kind of things. 'Turn left, and then move forward if there are no obstacles in the way' is a meaningful instruction, but one that would be very difficult for us to parse. Instead, we simplify the problem - we create a protocol for interacting with Pacman - a stripped down set of words to which Pacman will respond. This will be his command set - the list of orders to which he will respond. To begin with, we will make it simple and give him only three:
So, if the instruction the user provides isn't any of these, we present them with an error message. If it is one of these, we perform the desired command:
Run this, and we can actually issue a simple command to Pacman. Fantastic! Except, that if we issue something that is 'kind of' like an instruction he won't do anything. He understands 'right', but not 'Right' - that's because we are using .equals() for our method which is case sensitive. Let's change it to equalsIgnoreCase:
Super - but it's still not very robust. If we type " right" for example, it won't work - so let's trim the instructions before we attempt to parse it:
Now he'll accept instructions regardless of how sloppy they are formed - 'RIGht', " RighT " and any combination inbetween. Very nice indeed. Of course, he only accepts a single instruction before he gives up here - really, what we want to be able to do is keep issuing instructions until we're fed up... we can do this by adding in a fourth entry to our command set: STOP. We'll then put the prompting for instructions and the parsing of these instructions into a while loop - while the last command was not stop, we keep going. Except, how do we do that? We already know that != will not work on a string, and there is no doesNotEqual method. How do we check that something is not true if we only have a method to check if it is? We use the not operator to do this: ! . We say "while it is not true that instructions is equal to stop":
Like so:
And there we have it, simple instructions issued to Pacman - and it puts the orders on its skin or else it gets the hose again. Smashing!
We're lazy people, let's not deny it - and all that typing seems like work. Sure, Pacman will obey us, but couldn't we make it so that all we had to do was type in a list of instructions and he'd follow them? In fact, can't we just type in single letters and get him to follow them?
Couldn't he interpret that as 'move, move, left, move, move, stop'? That way we could get all of this done in an instant and then go off and do something else. Well, there is indeed a way you can do that, and it underlines the way Strings are structured... they are lists of alphanumeric data, and we can access each individual part of that list if we want to. The position that a letter has in a string is known as its index, and the letter at a particular index is known as an element. However, to be awkward, the first index in a string is 0, and so the first letter in a string has the index 0. Weird? Perhaps - but you'll get used to it. Each of the letters can be extracted from the string as a single char variable, and we use the charAt method in the string to do this. Taking the listOfInstructions variable above, if we wanted the first letter we could do something like this:
The letter variable would then contain the value 'm'. We know how to get the number of characters in a string - we use the length() variable. Perhaps then there's a way to step over each of the characters in the string and have him deal appropriately with the instructions? There is indeed, and it harks back to the idea of a for loop. A for loop is a bounded loop, and we need to know how many times we are going to repeat. And indeed we do - we have the number of letters in the string. We need a counter variable (we'll call this i), we know our termination condition (we'll continue looping while i is less than the number of letters in the string), and we know what our upkeep will be - our loop would look like this:
That seems easy enough - now it's just a case of pulling off the appropriate letter:
And then dealing with it. We'll use a switch statement for this:
Tada, and putting it all together we get the following program:
Run the program and input your instructions:
Hit return, and watch him wend his way through your instructions like a drunk trying to get home on a Saturday night:
That's not bad at all: A fully programmable pacman implemented in a few lines of code. It would be better if we could give him proper instructions though, such as 'move until you see an obstacle' or 'turn around', but we'll talk more about that in later chapters.
Strings are a very useful kind of data type, and give the developer enormous power over manipulation and modification of the data contained within. They are a complex data type, and there are dozens of more powerful methods available within (you'll find these discussed in some more depth in the Javanomicon), but even this overview of Strings gives you considerable flexibility in how you deal with the input sent into your pacman game from the user. Further ReadingThe following table details further reading on the topic in this chapter, and also any external resources that you may find useful.
|
| Previous | Table of Contents | Next |
© 2004-2006 Michael James Heron and Pauline Belford