Solved

How to split LPCTSTR with  MS C 2008?

Posted on 2011-09-14
25
1,121 Views
Last Modified: 2012-05-12
Dear experts!

I’m programmer with 10+ years in industry, but totally new to MS C 2008 and I need help.
I have a variable and here you a sample value
 LPCTSTR sPicFiles =”C:\Temp\Pic001.tif, C:\Temp\Pic002.tif, C:\Temp\Pic003.tif, C:\Temp\Pic004.tif”

I need a code which to give me follow functions:

1.      To split the sPicFiles to somethink like: sPic[0]= =”C:\Temp\Pic001.tif”, sPic[1]= =”C:\Temp\Pic002.tif” .

2.      The structure should be able to convert to LPCTSTR for single elements

3.      To have options to loop in structure in same order on which it is created

4.      I do not know how much elements I’ll have in structure, or may be I know if I count the comma before create the structure.

Please give me example code.
0
Comment
Question by:dvplayltd
  • 10
  • 7
  • 6
  • +1
25 Comments
 
LVL 15

Accepted Solution

by:
Minh Võ Công earned 250 total points
ID: 36541132
To split string by LPCTSTR you can use function _tcstok:
http://msdn.microsoft.com/en-us/library/2c8d19sb(v=vs.71).aspx
0
 
LVL 15

Expert Comment

by:Minh Võ Công
ID: 36541150
or you can convert it to CString
0
 
LVL 7

Expert Comment

by:tampnic
ID: 36541383
If you use the Boost library then the code snippet below will split the string directly into a vector array.

Its probably slower to execute than writing a function using _tcstok, but you will end up writing less code yourself and remember the STL vector will be taking care of memory management of the array for you.

#include <boost/algorithm/string.hpp>
std::vector<std::string> strs;
boost::split(strs, "string to tokenise", boost::is_any_of("\n\t "));


cout << strs[0];
cout << strs[1]; // etc etc

Open in new window


Cheers,
  Chris
0
 
LVL 7

Assisted Solution

by:tampnic
tampnic earned 83 total points
ID: 36541386
I should have changed the token characters in the code snippet - instead of boost::is_any_of("\n\t ") you should put boost::is_any_of(",") to delimit on a comma

Cheers,
 Chris
0
 

Author Comment

by:dvplayltd
ID: 36541704
To Chris

Look great! But seem to me that I should install additional library, is that correct?
0
 
LVL 7

Expert Comment

by:tampnic
ID: 36541929
Yes, you will need to install the Boost libraries from http://www.boost.org/ and set up your project to use them.

To be honest, in the short term for something as trivial as splitting a string into an array it might be just as quick to write your own code to use _tcstok as minhvc suggests. However in the long term the Boost libraries are a great thing to have around, very powerful and a lot of people use them so they are as solid as third-party libraries get.

Cheers,
  Chris
0
 
LVL 32

Assisted Solution

by:sarabande
sarabande earned 167 total points
ID: 36542167
you easily could split the string using std::string.

std::string s =”C:\\Temp\\Pic001.tif, C:\\Temp\\Pic002.tif, C:\\Temp\\Pic003.tif, C:\\Temp\\Pic004.tif”;
size_t p1 = 0, p2 = 0;
s += ", ";  // add separator at end
std::vector<std::string> spic;
while ((p2 = s.find(", ", p1)) != std::string::npos)
{
     if (p2 > p1)
          spic.push_back(s.substr(p1, p2-p1));
     p1 = p2+2;
}

Open in new window


note, you can get a LPCSTR from std::string by calling c_str() member function, for example like

LPCSTR p = spic[0].c_str();

Open in new window


the LPCTSTR is equivalent to LPCSTR when your project doesn't use UNICODE charset.

Sara
0
 

Author Comment

by:dvplayltd
ID: 36542441
To sara

Well, you answer look better then others. But I use Unicode, then? Please post change for Unicode and have great change to accept you answer.

For Chris - I do not want to include additional libraries (files) which to deploy, for minhvc - may be, but this is link only, not code as Sara did.
0
 

Author Comment

by:dvplayltd
ID: 36542467
To sara

Aaa. std is for C++, while I need C code. Correct?
0
 
LVL 7

Expert Comment

by:tampnic
ID: 36542671
str::string is C++, so are the Boost libraries. Unless the whole of your application is written in C for some reason, then I would not worry about introducing C++ constructs as Visual Studio 2008 should compile either. Here is a version of Sara's code which works with UNICODE - as the string is now made of TCHAR elements.

 
#include "stdafx.h"
#include <stdlib.h>
#include <Windows.h>
#include <tchar.h>
#include <string>
#include <vector>

int main()
{
	std::basic_string<TCHAR> s = _T("C:\\Temp\\Pic001.tif, C:\\Temp\\Pic002.tif, C:\\Temp\\Pic003.tif, C:\\Temp\\Pic004.tif");
	size_t p1 = 0, p2 = 0;
	s += _T(", ");  // add separator at end
	std::vector<std::basic_string<TCHAR>> spic;
		while ((p2 = s.find(_T(", "), p1)) != std::string::npos)
		{
			 if (p2 > p1)
				  spic.push_back(s.substr(p1, p2-p1));
			 p1 = p2+2;
		}
    return 0;
}

Open in new window


Cheers,
  Chris
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36542689
yes, both boost and stl is c++.

when using a .cpp fileextension the visual studio would automatically use c++ compiler. so it would not be very difficult to put the split function into a cpp source but call it from c sources.

the same code in pure c is more error-prone:

#define MAX_PIC 100
#define MAX_STR 1024

char s[MAX_STR] ={ '\0' };
size_t len = strlen(s);
char * p1 = NULL, * p2 = s;
char * spic[MAX_PIC] = { 0 };
int i = 0;

strcpy(s, ”C:\\Temp\\Pic001.tif, C:\\Temp\\Pic002.tif, C:\\Temp\\Pic003.tif, C:\\Temp\\Pic004.tif”);
len= strlen(s);

// add separator at end

s[len++] = ','; 
s[len++] = ' '; 

while ((p2 = strstr(p1, ", ")) != NULL)
{
     if (p2 > p1)
          spic[i++]  = p1; // store pointer to substring into array
     *p2 = '\0';           // terminate the sub string
      p1 = p2+2;        // next position
}

Open in new window


the code is not tested.

Sara
0
 
LVL 7

Expert Comment

by:tampnic
ID: 36542690
N.B. Sara I'm not trying to point grub here - your solution looks the best. I have time on my hands to add the unicode stuff to your code, points should still be yours.

Cheers,
  Chris
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 

Author Comment

by:dvplayltd
ID: 36543015
Well, I'm really confused. As I say, I'm new to C or C++

My C project send commands to extarnal device (a Stradis card). In the manual are written that I should use C in order to be OK with new version of drivers. It is written that if I use C++ my application will work only with 1 driver version .

I think that in a project I can't mix C and C++ code, right ??? But my files are all .cpp ..then = what is my project - C or C++ ???

P.S: I work on it 2 months and it is 90 % ready and work ... but I still do not know basic of C .. :-( :-( :-(
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36543132
if using visual studio and have not changed code generation in properties a cpp file will compiled with c++ compiler.

the 'driver' thing is wrong. there are no differences between c and c++ when using external resources/driver  beside of a external "C" directive to add (perhaps).

we all could help you with that.

Sara
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36543211
i don't think you wer using UNICODE now cause a statement like

LPCTSTR x = "whatever...";

would not compile. the LPCTSTR is const char * if ANSI character set and const wchar_t * if UNICODE (UTF16). the "whatever ..." is
const char *

Open in new window

while L"whatever " would be const wchar_t *.

microsoft switches the mapping of LPCTSTR depending on settings at properties - general - characterset of your project. you could use the TCHAR like tampnic showed if you ever intend to switch between character sets. if not i would go to ansi especially if you think you need c coding.

Sara
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36543256
note, c is a subset of c++ what means that whatever c library comes with your driver it could be called from either c++ or c.

if the header files that come with the driver are already made professional, they would work for both c and c++. if not, they are only made for access from c but that easily can be corrected by putting extern C" around the include:

extern "C"
{
#include "stradisheader.h"
}

Open in new window


Sara
0
 

Author Comment

by:dvplayltd
ID: 36544010
To minhvc

Look that in the end I'll accept your solution. Could you please correct follow example to Unicode ?

       char *strtok(
         char *strToken,
         const char *strDelimit
      );
      wchar_t *wcstok(
         wchar_t *strToken,
         const wchar_t *strDelimit
      );
      unsigned char *_mbstok(
         unsigned char*strToken,
         const unsigned char *strDelimit
      );

      char string[] = sPicFile; // "A string\tof ,,tokens\nand some  more tokens";
char seps[]   = " ,\t\n";
char *token;

   LPCTSTR sPic[999];

         token = strtok( string, seps );
   while( token != NULL )
   {
      /* While there are tokens in "string" */
      printf( " %s\n", token );
      /* Get next token: */
      token = strtok( NULL, seps );
   }
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36544217
the strtok or _tcstok for TCHAR strings is not quite suitable for you cause it cannot search for a separator which has two characters. if your sample is right you need a comma+space as separator.

you could use only the comma as separator and then increment the pointer to substring to skip a following space char. but that makes the code not easier.

i strongly recommend using either boost or my stl sample code. if you change the std::string type to std::basic_string<TCHAR> you also automatically have the UNICODE supported.

Sara
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36544235
tampnic has posted the code which uses std::basic_string<TCHAR>.

Sara
0
 
LVL 7

Expert Comment

by:tampnic
ID: 36544248
Sara's solution in message ID: 36542689 where she shows some C code to accomplish your task looks better than using a strtok mechanism - she's modifying the original string slightly , inserting null-characters where the delimiters used to be, and returning an array of pointers into the original string. Doesn't require extra memory allocation - I think it's an elegant idea. Here it is in UNICODE format.

#define MAX_PIC 100
	#define MAX_STR 1024

	wchar_t s[MAX_STR] ={ '\0' };
	size_t len = wcslen(s);
	wchar_t * p1 = s, * p2 = s;
	wchar_t * spic[MAX_PIC] = { 0 };
	int i = 0;

	wcscpy(s, L"C:\\Temp\\Pic001.tif, C:\\Temp\\Pic002.tif, C:\\Temp\\Pic003.tif, C:\\Temp\\Pic004.tif");
	len= wcslen(s);

	// add separator at end

	wcscat(s,L", ");; 

	while ( p2 = wcsstr(p1, L", ") )
	{
			if (p2 > p1)  spic[i++]  = p1; // store pointer to substring into array
			*p2 = '\0';           // terminate the sub string
			p1 = p2+sizeof(wchar_t);        // next position
	}

Open in new window


Cheers,
  Chris
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36544249
in your code using strtok you have the space char included into the separators. that will fail if you ever use file names or folder names that have a space char.

Sara
0
 
LVL 7

Expert Comment

by:tampnic
ID: 36544312
N.B. I tested the above code and the only changes to Sara's original were to initialise p1 differently to fix a bug and use wide character strings/functions throughout. There are minor improvements which could be arguably made e.g. use Microsoft's ahem "secure" variations of the standard C functions.

The idea behind that code is very nice. If I'm ever forced to write straight C again I will use it immediately. Personally I would use Boost as its set up on my machine, Sara's STL approach works just as well for me. She has explained how you can interface C++ code to a C library with the extern "C" directive. But if you *really need* straight C, I would go for the code in my last message.

Cheers,
   Chris
0
 
LVL 32

Assisted Solution

by:sarabande
sarabande earned 167 total points
ID: 36544317
strtok also uses the original buffer and doesn't need extra memory (beside of a static variable) same as my code. both also need a non-const buffer because of inserting zero characters to terminate the substrings. so you would need to use a TCHAR array or LPTSTR and not LPCTSTR (waht is const) when using _tcstok.

Sara
0
 

Author Closing Comment

by:dvplayltd
ID: 36545916
Yeee, this is probably bigger discussion from all my 400 questions in last 2 years.  Thanks to all for your time.

First – sorry – my example is not so correct. Here  more precise example of data:

sPic=”C:\Temp\logo001.tif, C:\Temp\logo002.tif, C:\Temp\logo003.tif”

The only separator which I’ll use it is , there will be no space between files. I do not need universal solution , I need solution for this case EXACLTY without add any additional libraries. All this become too theoretically, I need practical solution with minimum change  in installation and dependence of additional libraries. The Stradis card are hardware device, after a week test I release that  one major function of device work unstable because I compile under VC9, while it is design under VC6, you tell me to install additional libraries and to face with additional problems  and support in future – NO THANKS.  And this is only one case in which I need this, there will be no ANY other cases.

 All are welcome to question
http://www.experts-exchange.com/Programming/Languages/C/Q_27310275.html
0
 
LVL 32

Expert Comment

by:sarabande
ID: 36547384
vc6 also has std::string and std::vector. there is no additional library necessary.

the 'more precise example' you posted has same 'properties' as discussed: it misses the L"" or _T() specifier right-hand, so it only compiles for non-unicode. and it has a comma and a space character between files. the strtok will work nevertheless as long as you have no spaces in file or folder names. vc9 is much more stable than vc6 what is 10 years older. if you have problems with stability it comes from the driver and if you were lucky it only will get evident with vc9. but i wouldn't trust on it.

Sara
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use nested-loops in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now