Raised This Month: $ Target: $400
 0% 

Solved Parsing a string


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Ludak
Member
Join Date: Oct 2014
Old 03-08-2020 , 11:03   Parsing a string
Reply With Quote #1

Greetings,
I am trying to make a simple parser for this notation:

PHP Code:
Example 1"(some,(weird,string),list)"
Example 2"(some,weird,string,list)"
Example 3"(some,weird,string,list,(with,(more,random),words))" 
I want to split it to multiple parts separated by comma.
Let me give you an example:
For this input:
PHP Code:
(some,weird,string,list,(with,(more,random),words)) 
I want this output:
PHP Code:
some
weird
string
list
(
with,(more,random),words
I have written this code, but it gives me the error which I can not solve:
PHP Code:
#include <amxmodx>

#define MAX_PARTS                64
#define MAX_PART_LENGTH        256

public plugin_init() {
    
register_plugin("Text Parse Test""1.0""Author");
    
    
RunTests();
}

stock Parse(const text[], parts[][], partNumberspartLength) {
    if(!
IsValidFormat(text))
        return 
0;
        
    if(
partNumbers MAX_PARTS || partLength MAX_PART_LENGTH) {
        
partNumbers MAX_PARTS;
        
partLength MAX_PART_LENGTH;
    }
        
    new 
textLength strlen(text);
    new 
icurrentChar;
    new 
boolfoundFirst false;
    new 
boolinASubstring false;
    
    new 
tempPart 0;
    new 
tempParts[MAX_PARTS][MAX_PART_LENGTH];
    new 
tempLength 0;
    
    for(
0textLength++) {
        
currentChar text[i];
        
        
// Break if there are more than MAX_MARTS parts
        
if(tempPart MAX_PARTS)
            break;
    
        
// Skip first '('
        
if(!foundFirst && currentChar == '(') {
            
foundFirst true;
            continue;
        }
        
// Enter to the substring
        
else if(foundFirst && currentChar == '(')
            
inASubstring true;
        
        
// Skip last ')'
        
if(== textLength && currentChar == ')')
            continue;
            
        
// Exit the substring
        
else if(currentChar == ')')
            
inASubstring false;
        
        
// Skip ',' and move on to the next part if not in a substring
        
if(!inASubstring && currentChar == ',') {
            
tempParts[tempPart][tempLength] = EOS;
            
tempLength 0;
            
tempPart ++;
            continue;
        }
        
        
// Truncate over MAX_PART_LENGTH
        
if(tempLength MAX_PART_LENGTH) {
            
tempLength MAX_PART_LENGTH;
            
tempParts[tempPart][tempLength] = EOS;
            
tempLength 0;
            
tempPart ++;
            continue;
        }
        
        
tempParts[tempPart][tempLength ++] = currentChar;
    }
    
    for(new 
0partNumbers++)
        
copy(parts[x], partLengthtempParts[x]);
    
    return 
tempPart;
}

stock boolIsValidFormat(const text[]) {
    new 
fistParentheses indexOf(text'(');
    new 
lastParentheses lastIndexOf(text')');
    
    
// If the text does not contain '(' and ')' at all, abort
    
if(fistParentheses == -|| lastParentheses == -1)
        return 
false;
    
    
// If the text does not start with '(' and end with ')', abort
    
if(!(fistParentheses == && lastParentheses == strlen(text) - 1))
        return 
false;
    
    return 
true;
}

stock indexOf(const text[], const characterboollast false) {
    new 
textLength strlen(text);
    new 
ilastIndex = -1;
    
    for(
0textLength++) {
        if(
text[i] == character) {
            
lastIndex i;
            
            if(!
last)
                break;
        }
    }
    
    return 
lastIndex;
}

stock lastIndexOf(const text[], const character)
    return 
indexOf(textcharactertrue);
    
stock RunTests() {
    
TestIndexOf("indexOf & lastIndexOf");
    
TestValidFormat("valid format");
    
TestParse("parse");
}

stock TestIndexOf(const test[]) {
    new 
text[64];
    
copy(textcharsmax(text), "(some,(weird,string),list)");
    
    
server_print("[Test: %s] Text: %s (Length: %d) - Found '(': %s (%d) | Found: ')': %s (%d) - Is accurate: %s"test,
        
textstrlen(text), indexOf(text'(') != -"Yes" "No"indexOf(text'('), lastIndexOf(text')') != -"Yes" "No"
        
lastIndexOf(text')'), indexOf(text'(') == && lastIndexOf(text')') == 25 "Yes" "No" );
}

stock TestValidFormat(const test[]) {
    new 
sample[4][64];
    
copy(sample[0], charsmax(sample[]), "(some,(weird,string),list)");
    
copy(sample[1], charsmax(sample[]), "(some,(weird,string),list");
    
copy(sample[2], charsmax(sample[]), "some,(weird,string),list)");
    
copy(sample[3], charsmax(sample[]), "some,(weird,string),list");
    
    for(new 
04++)
        
server_print("[Test: %s] Sample %d is valid format?: %s"test1IsValidFormat(sample[i]) ? "Yes" "No");
}

stock TestParse(const test[]) {
    new 
text[512];
    
copy(textcharsmax(text), "(some,(weird,string),list,1234,,(more,text,in,a,substring),some,more,$$$,###,@annotation)");
    new 
parts[12][128];
    
    new 
partsNumber Parse(textparts12128);
    
    if(
partsNumber 0) {
        for(new 
0partsNumber++)
            
server_print("[Test: %s] Parsed part %d/%d: %s"testipartsNumberparts[i]);
    } else 
server_print("[Test: %s] Failed to parse, 0 parts returned!"test);

Error:
PHP Code:
L 03/08/2020 15:48:09Start of error session.
L 03/08/2020 15:48:09Info (map "de_dust2") (file "addons/amxmodx/logs/error_20200308.log")
L 03/08/2020 15:48:09: [AMXXDisplaying debug trace (plugin "test_parse.amxx")
L 03/08/2020 15:48:09: [AMXXRun time error 3stack error 
L 03
/08/2020 15:48:09: [AMXX]    [0parser.sma::Parse (line 27)
L 03/08/2020 15:48:09: [AMXX]    [1parser.sma::TestParse (line 145)
L 03/08/2020 15:48:09: [AMXX]    [2parser.sma::RunTests (line 117)
L 03/08/2020 15:48:09: [AMXX]    [3parser.sma::plugin_init (line 9
I know this has to do somthing with the stack of the Pawn Amxx VM, but I am not sure what is the exact problem.
I have tried this, but got the same resoults:
PHP Code:
#define MAX_PARTS                64
#define MAX_PART_LENGTH        256 
Can you help me?
Thank you.

Last edited by Ludak; 03-21-2020 at 06:27.
Ludak is offline
fysiks
Veteran Member
Join Date: Sep 2007
Location: Flatland, USA
Old 03-08-2020 , 17:53   Re: Parsing a string
Reply With Quote #2

You're trying to declare a 65+ MB array. Have you tried something smaller? Also, I'm quire sure that you can do this without limiting the number of items that can be found in your string (in the context of the Parse() function at least).
__________________
fysiks is offline
Ludak
Member
Join Date: Oct 2014
Old 03-08-2020 , 19:03   Re: Parsing a string
Reply With Quote #3

Quote:
Originally Posted by fysiks View Post
You're trying to declare a 65+ MB array. Have you tried something smaller? Also, I'm quire sure that you can do this without limiting the number of items that can be found in your string (in the context of the Parse() function at least).
So as I understood correcty that is like 64 * cell size * 256 = 65 MB?
I tried [12][64], gives me the same error.
I am not experienced in pawn, can I do something like puting the parsed part into temp string, then doing something like:
PHP Code:
copy(parts[someIncrement ++], partLengthtempString); 
?
Ludak is offline
fysiks
Veteran Member
Join Date: Sep 2007
Location: Flatland, USA
Old 03-08-2020 , 19:16   Re: Parsing a string
Reply With Quote #4

Here is how I would do it but note that I excluded the outer parentheses requirement because it makes no sense (it's an inconsistent use of the parentheses). This requires no temporary strings and is only limited by the results array passed into the function.

PHP Code:
stock Parse(const text[], results[][], resultCountmaxlen)
{
    new 
index 0
    
new iItems 0
    
new iStartIndex 0iLen 0
    
new iParenCounter 0

    
while( text[index] != EOS && iItems resultCount )
    {
        
        if( 
text[index] == '(' )
        {
            
iParenCounter++
        }
        if( 
text[index] == ')' )
        {
            
iParenCounter--
        }
        
        if( (
text[index] == ',' || text[index+1] == EOS) && iParenCounter == )
        {
            
iLen index iStartIndex + (text[index+1] == EOS 0)
            
copy(results[iItems++], min(maxleniLen), text[iStartIndex])
            
iStartIndex index 1
        
}
        
        
index++
    }
    
    return 
iItems

If for some reason you still want the outer parentheses, you can remove them before passing to this function.
__________________

Last edited by fysiks; 03-08-2020 at 19:20.
fysiks is offline
Ludak
Member
Join Date: Oct 2014
Old 03-08-2020 , 19:23   Re: Parsing a string
Reply With Quote #5

Quote:
Originally Posted by fysiks View Post
Here is how I would do it but note that I excluded the outer parentheses requirement because it makes no sense (it's an inconsistent use of the parentheses). This requires no temporary strings and is only limited by the results array passed into the function.

PHP Code:
stock Parse(const text[], results[][], resultCountmaxlen)
{
    new 
index 0
    
new iItems 0
    
new iStartIndex 0iLen 0
    
new iParenCounter 0

    
while( text[index] != EOS && iItems resultCount )
    {
        
        if( 
text[index] == '(' )
        {
            
iParenCounter++
        }
        if( 
text[index] == ')' )
        {
            
iParenCounter--
        }
        
        if( (
text[index] == ',' || text[index+1] == EOS) && iParenCounter == )
        {
            
iLen index iStartIndex + (text[index+1] == EOS 0)
            
copy(results[iItems++], min(maxleniLen), text[iStartIndex])
            
iStartIndex index 1
        
}
        
        
index++
    }
    
    return 
iItems

If for some reason you still want the outer parentheses, you can remove them before passing to this function.
Thanks for the help, meanwhile I managed to get it working, I' am going to use your version.

PHP Code:
#include <amxmodx>


#define MAX_PARTS                64
#define MAX_PART_LENGTH        256

public plugin_init() {
    
register_plugin("Text Parse Test""1.0""Author");
    
    
RunTests();
}

stock Parse(const text[], parts[][], partNumberspartLength) {
    if(!
IsValidFormat(text))
        return 
0;
        
    new 
textLength strlen(text);
    new 
icurrentChar;
    new 
boolfoundFirst falseboolinASubstring false;
    
    new 
tempNumber 0tempLength 0;
    new 
tempPart[MAX_PART_LENGTH];
    
    for(
0textLength++) {
        
currentChar text[i];
        
        if(
tempNumber partNumbers)
            break;
    
        
// Skip first '('
        
if(!foundFirst && currentChar == '(') {
            
foundFirst true;
            continue;
        }
        
// Enter to the substring
        
else if(foundFirst && currentChar == '(')
            
inASubstring true;
        
        
// Skip last ')'
        
if(== textLength && currentChar == ')')
            continue;
            
        
// Exit the substring
        
else if(currentChar == ')')
            
inASubstring false;
        
        
// Skip ',' and move on to the next part if not in a substring
        
if(!inASubstring && currentChar == ',') {
            
tempPart[tempLength] = EOS;
            
copy(parts[tempNumber ++], partLengthtempPart)
            
tempLength 0;
            continue;
        }
        
        
// Truncate over MAX_PART_LENGTH
        
if(tempLength MAX_PART_LENGTH) {
            
tempLength MAX_PART_LENGTH;
            
tempPart[tempLength] = EOS;
            
copy(parts[tempNumber ++], partLengthtempPart)
            
tempLength 0;
            continue;
        }
        
        
tempPart[tempLength ++] = currentChar;
    }
    
    return 
tempNumber;
}

stock boolIsValidFormat(const text[]) {
    new 
fistParentheses indexOf(text'(');
    new 
lastParentheses lastIndexOf(text')');
    
    
// If the text does not contain '(' and ')' at all, abort
    
if(fistParentheses == -|| lastParentheses == -1)
        return 
false;
    
    
// If the text does not start with '(' and end with ')', abort
    
if(!(fistParentheses == && lastParentheses == strlen(text) - 1))
        return 
false;
    
    return 
true;
}

stock indexOf(const text[], const characterboollast false) {
    new 
textLength strlen(text);
    new 
ilastIndex = -1;
    
    for(
0textLength++) {
        if(
text[i] == character) {
            
lastIndex i;
            
            if(!
last)
                break;
        }
    }
    
    return 
lastIndex;
}

stock lastIndexOf(const text[], const character)
    return 
indexOf(textcharactertrue);
    
stock RunTests() {
    
TestIndexOf("indexOf & lastIndexOf");
    
TestValidFormat("valid format");
    
TestParse("parse");
}

stock TestIndexOf(const test[]) {
    new 
text[64];
    
copy(textcharsmax(text), "(some,(weird,string),list)");
    
    
server_print("[Test: %s] Text: %s (Length: %d) - Found '(': %s (%d) | Found: ')': %s (%d) - Is accurate: %s"test,
        
textstrlen(text), indexOf(text'(') != -"Yes" "No"indexOf(text'('), lastIndexOf(text')') != -"Yes" "No"
        
lastIndexOf(text')'), indexOf(text'(') == && lastIndexOf(text')') == 25 "Yes" "No" );
}

stock TestValidFormat(const test[]) {
    new 
sample[4][64];
    
copy(sample[0], charsmax(sample[]), "(some,(weird,string),list)");
    
copy(sample[1], charsmax(sample[]), "(some,(weird,string),list");
    
copy(sample[2], charsmax(sample[]), "some,(weird,string),list)");
    
copy(sample[3], charsmax(sample[]), "some,(weird,string),list");
    
    for(new 
04++)
        
server_print("[Test: %s] Sample %d is valid format?: %s"test1IsValidFormat(sample[i]) ? "Yes" "No");
}

stock TestParse(const test[]) {
    new 
text[512];
    
copy(textcharsmax(text), "(some,(weird,string),list,1234,,(more,text,in,a,substring),some,more,$$$,###,@annotation)");
    new 
parts[12][128];
    
    new 
partsNumber Parse(textparts12128);
    
    if(
partsNumber 0) {
        for(new 
0partsNumber++)
            
server_print("[Test: %s] Parsed part %d/%d: %s"testipartsNumberparts[i]);
    } else 
server_print("[Test: %s] Failed to parse, 0 parts returned!"test);

PHP Code:
[TestindexOf lastIndexOfText: (some,(weird,string),list) (Length26) - Found '('Yes (0) | Found')'Yes (25) - Is accurateYes
[Testvalid formatSample 1 is valid format?: Yes
[Testvalid formatSample 2 is valid format?: No
[Testvalid formatSample 3 is valid format?: No
[Testvalid formatSample 4 is valid format?: No
[TestparseParsed part 0/10some
[TestparseParsed part 1/10: (weird,string)
[
TestparseParsed part 2/10: list
[
TestparseParsed part 3/101234
[TestparseParsed part 4/10
[
TestparseParsed part 5/10: (more,text,in,a,substring)
[
TestparseParsed part 6/10some
[TestparseParsed part 7/10more
[TestparseParsed part 8/10: $$$
[
TestparseParsed part 9/10### 

Last edited by Ludak; 03-08-2020 at 19:24.
Ludak is offline
Natsheh
Veteran Member
Join Date: Sep 2012
Old 03-09-2020 , 02:51   Re: Parsing a string
Reply With Quote #6

I'd suggest using regex it's much easier.
__________________
@Jailbreak Main Mod v2.7.0 100%
@User Tag Prefix 100% done !
@Mystery Box 100% done !
@VIP System 100% done !

Natsheh is offline
Send a message via MSN to Natsheh Send a message via Skype™ to Natsheh
fysiks
Veteran Member
Join Date: Sep 2007
Location: Flatland, USA
Old 03-09-2020 , 22:19   Re: Parsing a string
Reply With Quote #7

Quote:
Originally Posted by Natsheh View Post
I'd suggest using regex it's much easier.
If it's that much easier, let's see how you'd do it with regex. Also, there is more overhead for regex so it might not be more efficient considering this isn't all that complicated of string processing.
__________________
fysiks is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 14:49.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode