472,995 Members | 1,547 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,995 software developers and data experts.

Switching on strings...

What would be the best way to switch program flow based on a string the user
enters? I found out the hard way that char*'s can't be used in a switch
statement, so i've resorted to stringing if-else statements together. Is
there a more efficient way to do this?

Thanks
slick_shoes
Jul 19 '05 #1
4 37250
"slick_shoes" wrote:
What would be the best way to switch program flow based on a string the user enters? I found out the hard way that char*'s can't be used in a switch
statement, so i've resorted to stringing if-else statements together. Is
there a more efficient way to do this?


You can use std::map<std::string, functionpointer> to do this:

std::map<std::string, void(*)(void)> x;
x["bar"]=&function1;
x["foo"]=&function2; //and so on

//in input routine:
std::string input;
if(x.find(input)==x.end()) error(); // invalid input
x[input](); // calls the associated function
Jul 19 '05 #2

"slick_shoes" <sl*********@punkass.com> wrote in message
news:Ym***************@news.randori.com...
What would be the best way to switch program flow based on a string the user enters? I found out the hard way that char*'s can't be used in a switch
statement, so i've resorted to stringing if-else statements together. Is
there a more efficient way to do this?

Thanks
slick_shoes


You *could* do a switch statement, e.g.

char MyString[100]; // or whatever

switch (MyString[0])
{
case 'A':
// do whatever
break;
case 'B':
// do whatever
break;
case 'C':
switch (MyString[1])
{
case 'A':
// do whatever
break;
case 'B':
// do whatever
break;
}
}

Although this is quite messy. You could also set up an array of char[]
which may contain the first few letters of the string to decide which way to
switch, then loop through these with strncmp() and get the index, then
switch on the index
Allan

Jul 19 '05 #3
"slick_shoes" <sl*********@punkass.com> wrote in message news:<Ym***************@news.randori.com>...
What would be the best way to switch program flow based on a string the user
enters? I found out the hard way that char*'s can't be used in a switch
statement, so i've resorted to stringing if-else statements together. Is
there a more efficient way to do this?

To emulate a switch statement on string, I propose you a solution that
consists of:
- converting a string to a (non unique) integral value,
- using a switch statement on the value,
- resolving value-equivalence conflicts,
with no hand-typed code to implement these points. Just specify the
case labels and type the specific code for each of them.

To do it simpler, we'll suppose that each case block ends with a break
statement.

You'll just have to type the following lines by hand:
//##markup##"switch(<your-string-expression>)"
//##data##
//<case-label-1>
//...
//<case-label-n>
//##data##
and you'll obtain by code generation:
//##markup##"switch(<your-string-expression>)"
//##data##
//<case-label-1>
//...
//<case-label-n>
//##data##
//##begin##"switch(<your-string-expression>)"
{
// Computes a hashcode for <your-string-expression>
int iHashCode = 0;
std::string sKey = <your-string-expression>;
for (int i = 0; i < sKey.size(); i++) {
unsigned char c = sKey[i];
iHashCode = (31*iHashCode + (c%31)) % 64000000;
}
// if true, no case label have matched
bool bDefault = false;
//
switch(iHashCode) {
case <case-value-1>: // "<case-label-1>"
if (sKey == "<case-label-1>") {
//##protect##"case \"<case-label-1>\":"
//##protect##"case \"<case-label-1>\":"
} else { bDefault = true;
}
break;
...
case <case-value-n>: // "<case-label-n>"
if (sKey == "<case-label-n>") {
//##protect##"case \"<case-label-n>\":"
//##protect##"case \"<case-label-n>\":"
} else { bDefault = true;
}
break;
default:
bDefault = true;
}
if (bDefault) {
//##protect##"default:"
//##protect##"default:"
}
}
//##markup##"switch(<your-string-expression>)"

Example:
* Suppose that you want to write something like it:
switch(sText) {
case "Product":
...
break;
case "Customer":
...
break;
case "Figuring":
...
break;
default:
...
}

* Then write:
//##markup##"switch(sText)"
//##data##
//Product
//Customer
//Figurine
//##data##
* Which becomes:
//##markup##"switch(sText)"
//##data##
//Product
//Customer
//Figurine
//##data##
//##begin##"switch(sText)"
{
int iHashCode = 0;
std::string sKey = sText;
for (int i = 0; i < sKey.size(); i++) {
unsigned char c = sKey[i];
iHashCode = (31*iHashCode + (c%31)) % 64000000;
}
bool bDefault = false;
switch(iHashCode) {
case 17133617: // "Product"
if (sKey == "Product") {
//##protect##"case \"Product\":"
//##protect##"case \"Product\":"
} else { bDefault = true;
}
break;
case 26793087: // "Customer"
if (sKey == "Customer") {
//##protect##"case \"Customer\":"
//##protect##"case \"Customer\":"
} else { bDefault = true;
}
break;
case 20050752: // "Figurine"
if (sKey == "Figurine") {
//##protect##"case \"Figurine\":"
//##protect##"case \"Figurine\":"
} else { bDefault = true;
}
break;
default:
bDefault = true;
}
if (bDefault) {
//##protect##"default:"
//##protect##"default:"
}
}
//##end##"switch(sText)"
The specific code for each case must be written in protected
areas (bounded with //##protect##...) so that the generator
preserves them from a generation to another.

But what about the generator? We'll use a LGPL tool devoted
to work on generative programming and called 'CodeWorker',
available at "http://www.codeworker.org".

We'll write our tailor-made code generation in the scripting
language of CodeWorker. The following script looks like
a server page syntax: raw text with instructions inlayed into.
Here, instructions of the scripting language are put between
the symbol '@'. If you are interested in understanding the
script in detail, I could give you some explanations about it.
We'll call the script "script.gen":
{
int iHashCode = 0;
std::string sKey = @coreString(getMarkupKey(), 7, 1)@;
for (int i = 0; i < sKey.size(); i++) {
unsigned char c = sKey[i];
iHashCode = (31*iHashCode + (c%31)) % 64000000;
}
bool bDefault = false;
switch(iHashCode) {
@
local codes;
local sData = getMarkupValue();
while sData {
local iIndex = sData.findString('\n');
if $iIndex < 0$ || !sData.startString("//") error("syntax error");
local sKey = sData.midString(2, $iIndex - 2$);
if sKey.endString('\r') set sKey = sKey.rsubString(1);
local iHashCode = 0;
local i = 0;
while $i < sKey.length()$ {
local c = sKey.charAt(i);
iHashCode = $(31*iHashCode + (c.charToInt()%31)) % 64000000$;
increment(i);
}
pushItem codes[iHashCode].keys = "\"" + composeCLikeString(sKey) +
"\"";
set sData = sData.subString($iIndex + 1$);
}
foreach i in codes {
@ case @key(i)@: // @
foreach j in i.keys {
if !first(j) {
@, @
} @@j@@
}
@
@
foreach j in i.keys {
@ @
if !first(j) {
// resolve hashcode conflicts between 2 labels
@} else @
}
@if (sKey == @j@) {
@
setProtectedArea("case " + j + ":");
}
@ } else {
bDefault = true;
}
break;
@
}
@ default:
bDefault = true;
}
if (bDefault) {
@
setProtectedArea("default:");
@ }
}

Now, just type the following line on the console:
CodeWorker -expand script.gen <your-C++-file>

CodeWorker expands the lines you have typed at the beginning
in the developed form, following the directives of "script.gen".
You can add/remove as many case labels as you want, even after having
expanded the C++ file, with no loss of source code. You just have
to type the precedent command line to take it into account.
If you change a label, don't forget to change the name of the
corresponding protected area as well.

Now, we can extend easily our switch statement for not being obliged
to have a break statement at the end of each case block:
- in "script.gen", replace:
bool bDefault = false;
by:
int iRank;
- each if statement implements the line:
iRank = <rank-of-case-label>; // [1..n]
- replace:
bDefault = true;
by:
iRank = 0;
- add a second switch behind the first one, applied on iRank.
- moves the protected areas to each case and to default.

-- Cedric
Jul 19 '05 #4
fred
1
below is a C++ program that shows a very easy way to switch on strings:

//---- Switch/case statments on strings - a workable solution (2/2006):
#include <iostream.h>
#include <stdlib.h>
using namespace std;

//------------------------------------------------------------------------------
//---- Given an array of string pointers, compare a subject string against
// that array. Function returns with the index to the list of subject
// strings.
// If a match is
// 1) found : return the index of the matched string plus 1
// 2) not found: return "0"
int sw(char *table[], const char *str, const int &entries)
{char **bp;
int i;
for(i=0,bp=&table[0]; i<entries; ++i,++bp) // scan all test strings
{if(*str != **bp)continue; // 1st char's must match
if(strcmp(str,*bp)==0)return i+1; // match whole string
}
return 0;
}
//------------------------------------------------------------------------------
int main(int argc, char *argv[])
{int i;
char in[64];

#define SIZE 6
char *array[SIZE]={"first","second","third","fourth","fifth","sixth "};

while (true)
{cout << "Please enter a string (\"enter\" only to terminate): ";
cin.getline(in, 64);

i=sw(array, in, SIZE);
switch(i)
{case 1:cout << in << "=" << i << endl;break;
case 2:cout << in << "=" << i << endl;break;
case 3:cout << in << "=" << i << endl;break;
case 4:cout << in << "=" << i << endl;break;
case 5:cout << in << "=" << i << endl;break;
case 6:cout << in << "=" << i << endl;break;
default:
if(strlen(in)<1)exit(0);
cout << "ERROR: " << "\"" << in << "\"" << endl;
}
}
}
Feb 28 '06 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Dennis Wheeler | last post by:
I'm trying to find a commandline solution for switching projects. Currently I have to modify the IIS virtual directory path to the source files, and then open the solution file in .Net to be...
1
by: Randy | last post by:
Access= 2002 I'm NOT a Programmer, but I have used VB in the past to do some things ( Spaghetti Code King) so I have some understanding of Coding I need to replace a text field (teacher) in...
16
by: agay | last post by:
Hi, I would like to get feedback on a "switching on strings" utility: http://shum.huji.ac.il/~agay/sos Thanks a. agay
1
by: TeeCo | last post by:
Hi folks. I'm trying to change the location of the Access mdb file I connect to using OleDb and am having trouble. I'm using Visual C# 2005 and the default values I use for the ConnectionString...
1
by: marcwentink | last post by:
Hi, In my ASP.NET application I and others before me have made to language resource files: strings.resx and strings.en.resx Now I can remember something about location and general settings...
2
by: Frank Swarbrick | last post by:
I had asked a question a few weeks ago about having problems at times accessing DB2 Express-C 9.1, and getting "SQL1032N No start database manager command was issued. SQLSTATE=57019" even when the...
3
by: Katie87 | last post by:
Hey, i have to write a program in which we will apply the same code to 5 different strings. The thing is were not allowed to write the code more than once, and our output has to be given for each...
1
by: Dave Rado | last post by:
Hi A while ago I discovered a way of creating css pseudo-frames, that offer users the important benefits of real frames (i.e. the navigation remains visible when you scroll down the page), but...
4
by: adlloyd | last post by:
Hi all, I've got an application that's written in C++ making use of MFC (VS6). Its purpose is to process SMS messages received from a GSM modem connected via a serial port (USB connection). The...
0
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
0
by: Aliciasmith | last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
1
by: Teri B | last post by:
Hi, I have created a sub-form Roles. In my course form the user selects the roles assigned to the course. 0ne-to-many. One course many roles. Then I created a report based on the Course form and...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 1 Nov 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM) Please note that the UK and Europe revert to winter time on...
0
isladogs
by: isladogs | last post by:
The next online meeting of the Access Europe User Group will be on Wednesday 6 Dec 2023 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, Mike...
4
by: GKJR | last post by:
Does anyone have a recommendation to build a standalone application to replace an Access database? I have my bookkeeping software I developed in Access that I would like to make available to other...
3
SueHopson
by: SueHopson | last post by:
Hi All, I'm trying to create a single code (run off a button that calls the Private Sub) for our parts list report that will allow the user to filter by either/both PartVendor and PartType. On...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.