Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ExtractStrings(...) Question

30 views
Skip to first unread message

brian

unread,
Feb 8, 2006, 4:16:09 PM2/8/06
to

Is there an ExtractStrings equivalent that will not skip
'sections' that contain NULL values? As an example, say I have a
string containing A:B:C::E and use ExtractStrings with the
delimiter being ':'. The result set will show 4 strings, not 5
(with strings[3] being empty) as I would prefer.

Thanks.

Remy Lebeau (TeamB)

unread,
Feb 8, 2006, 8:20:46 PM2/8/06
to

"brian" <Br...@nospam.org> wrote in message
news:43ea2759$1...@newsgroups.borland.com...

> Is there an ExtractStrings equivalent that will not skip
> 'sections' that contain NULL values?

Try using the Delimiter and DelimitedText properties of TStringList.

TStringList *Temp = new TStringList;
try
{
Temp->Delimiter = ':';
Temp->DelimitedText = "A:B:C::E";
Dest->AddStrings(Temp);
}
__finally {
delete Temp;
}

If that still does not suit yor needs, then you will just have to parse the
string manually to get what you need.


Gambit


Vladimir Stefanovic

unread,
Feb 8, 2006, 9:26:00 PM2/8/06
to
If you want to make the function yourself, you can do
something like this:

// Edit1->Text = "A:B:C::E"
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ParseAnsiStringToStrings( Edit1->Text, ':', ListBox1->Items );
}
// Reverse operation
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Edit2->Text = StringsToAnsiString( ListBox1->Items, ':' );
}

void TForm1::ParseAnsiStringToStrings( AnsiString AString, char AChar,
TStrings *AStrings )
{
if ( AString.Length() == 0 )
return;

AString = AString + AChar;

AStrings->Clear();

char *niz = new char[ AString.Length() + 1 ];
char *pom = new char[ AString.Length() + 1 ];

strcpy( niz, AString.c_str() );

int prev = 0;

for ( int i=0; i<AString.Length(); i++ )
{
if ( ( niz[i] == AChar ) || ( i == AString.Length()-1 ) )
{
strncpy( pom, &niz[prev], i-prev );
pom[i-prev] = '\0';

if ( AnsiString( pom ).Length() > 0 ) // <--- if NULL do nothing
AStrings->Add( AnsiString( pom ) );

prev = i + 1;
}
}

delete [] pom;
delete [] niz;
}

AnsiString TForm1::StringsToAnsiString( TStrings *AStrings, char AChar )
{
AnsiString Delimited;
for ( int i=0; i<AStrings->Count; i++ )
Delimited += AStrings->Strings[i] + AChar;

Delimited.SetLength( Delimited.Length()-1 );
return( Delimited );
}


--
Best regards,
Vladimir Stefanovic


Hans Galema

unread,
Feb 8, 2006, 10:50:09 PM2/8/06
to
Vladimir Stefanovic wrote:

> void TForm1::ParseAnsiStringToStrings( AnsiString AString, char AChar,
> TStrings *AStrings )
> {

> AString = AString + AChar;

That was a good idea!

But for the rest too complex.

AStrings->Clear();

if ( AString.Length() == 0 )
return;

AString = AString + AChar; // that was a good idea!

int start = 1;
int pos = 0;

int length = AString.Length(); //only call the Length() function once

while ( ++ pos <= length )
{
if ( AString[pos] == AChar )
{
AStrings->Add ( AString.SubString ( start, pos-start ) );

start = pos + 1;
}
}
}

Hans.

Remy Lebeau (TeamB)

unread,
Feb 8, 2006, 11:23:33 PM2/8/06
to

"Vladimir Stefanovic" <anti...@po.sbb.co.yu> wrote in message
news:43ea...@newsgroups.borland.com...

> If you want to make the function yourself, you can do
> something like this:

This would be a bit more accurate, and more memory efficient:

int __fastcall SeparateStrings(const AnsiString &AString, char
ADelimiter, TStrings *AStrings)
{
int Result = 0;

if( (AString.Length() > 0) && (AStrings) )
{
AStrings->BeginUpdate();
try
{
char *ptr = const_cast<AnsiString&>(AString).c_str();
char *end = (ptr + AString.Length());

while( (*ptr <= ' ') && (ptr < end) )
++ptr;

char *start = ptr;
bool InQuote = false;

while( ptr < end )
{
if( (*ptr == ADelimiter) && (!InQuote) )
{
AStrings->Add(AnsiString(start, ptr-start));
++Result;
start = ++ptr;
}

else if( *ptr == '"' )
{
InQuote = !InQuote;
++ptr;
}

else
++ptr;
}

if( start < end )
{
AStrings->Add(AnsiString(start, end-start));
++Result;
}
}
__finally {
AStrings->EndUpdate();
}
}

return Result;
}

AnsiString __fastcall JoinStrings(TStrings *AStrings, char ADelimiter)
{
AnsiString Result;

if( AStrings )
{
int Count = AStrings->Count;
if( Count > 0 )
{
int Len = (Count-1);
AnsiString S;

for(int i = 0; i < Count; ++i)
{
S = AStrings->Strings[i];
if( (S.Pos(ADelimiter) != 0) && (S[1] != '"') )
S = AnsiQuotedStr(S, '"');

Len += S.Length();
}

Result.SetLength(L);
char *ptr = Result.c_str();

for(int i = 0; i < Count; ++i)
{
if( i != 0 )
*ptr++ = ADelimiter;

S = AStrings->Strings[i];
if( (S.Pos(ADelimiter) != 0) && (S[1] != '"') )
S = AnsiQuotedStr(S, '"');

if( S.Length() > 0 )
{
StrLCopy(ptr, S.c_str(), S.Length());
ptr += S.Length();
}
}
}
}

return Result;
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{

ListBox1->Clear()
SeparateStrings(Edit1->Text, ':', ListBox1->Items);
}

void __fastcall TForm1::Button2Click(TObject *Sender)
{

Edit2->Text = JoinStrings(ListBox1->Items, ':');
}


> if( AnsiString( pom ).Length() > 0 ) // <--- if NULL do nothing

You are doing the very thing that Brian wants to void. If you are not going
to store empty strings, then there is no point in writing a replacement for
ExtractStrings() since it already ignores empty strings.


Gambit


Vladimir Stefanovic

unread,
Feb 9, 2006, 2:35:50 PM2/9/06
to
Yes, I know the code can be much more effective.
I just rearanged my old code.

Thanks.

Vladimir Stefanovic

unread,
Feb 9, 2006, 2:34:04 PM2/9/06
to
> You are doing the very thing that Brian wants to void.

That's my bad understanding of english :)

Brian

unread,
Feb 9, 2006, 7:59:51 PM2/9/06
to

"brian" <Br...@nospam.org> wrote:

Wow. Thanks for all the feedback!

captnKirk

unread,
Feb 10, 2006, 7:50:57 PM2/10/06
to

"Remy Lebeau \(TeamB\)" <no....@no.spam.com> wrote:

>Try using the Delimiter and DelimitedText properties of TStringList.
>
> TStringList *Temp = new TStringList;
> try
> {
> Temp->Delimiter = ':';
> Temp->DelimitedText = "A:B:C::E";
> Dest->AddStrings(Temp);
> }
> __finally {
> delete Temp;
> }

OR more simply:

TStringList *Tmp = new TStringList;
Tmp->Text = StringReplace(originalString,
":",
"\r\n",
TReplaceFlags()<<rfReplaceAll);

Happy Voyage,
The Capt'n

0 new messages