Link to home
Start Free TrialLog in
Avatar of fjocke
fjocke

asked on

C# Regex out a number from a string and then divide it

item_make_list={} corpse_make_list={{[cokacola];5;5;5.6617};{[redbul];1;1;100};{[moon];1;1;22.6465}} additional_make_list={}additional_make_multi_list={{{{[kebab];150;210;100}};70};{{{[kebab_meat];1;1;30.9859};{[kebab_magic];1;1;23.0047};{[magic_kebab];1;1;46.0094}};100};{{{[sauce];5;5;5.82524};{[roster];5;5;2.91262};{[whiskey];5;5;1.94174};{[claymore];5;5;1.16504};{[rocket];5;5;5.82524};{[mouse];1;1;11.6506}};33.494}}";

What i want todo, is using regex to get out certain values and then divide them or multiply them.
For instance if i write it like this:

            string txt = "item_make_list={} corpse_make_list={{[cokacola];5;5;5.6617};{[redbul];1;1;100};{[moon];1;1;22.6465}} additional_make_list={}additional_make_multi_list={{{{[kebab];150;210;100}};70};{{{[kebab_meat];1;1;30.9859};{[kebab_magic];1;1;23.0047};{[magic_kebab];1;1;46.0094}};100};{{{[sauce];5;5;5.82524};{[roster];5;5;2.91262};{[whiskey];5;5;1.94174};{[claymore];5;5;1.16504};{[rocket];5;5;5.82524};{[mouse];1;1;11.6506}};33.494}}";
            Regex regex = new Regex("([-+]?\\d+)", RegexOptions.IgnoreCase | RegexOptions.Singleline);
            string result = regex.Replace(txt, "6");//new MatchEvaluator (Replacement));
           listBox2.Items.Add(result);

It will replace all the int values with 6 in the string. But what i want todo is to firstly pick out everything that comes after a ; and then either divide them or multiply them depending on what.
And if its a float value like 5.6617 it should take the full value and multiply or divide it.

So, how do i make the value picked out by regex into a int, divide it or multiply it and then press it back in again?

Thanks


ASKER CERTIFIED SOLUTION
Avatar of Fernando Soto
Fernando Soto
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of fjocke
fjocke

ASKER

Thanks a bunch. I've not tested it yet, but it seems to be what im looking for
Avatar of fjocke

ASKER

There is still one thing you missed, the actual thing to get out only numbers that comes after a ;
Cause the string example i gave, was only a small part of the actual string.
So the regex needs a look-over aswell, if you would be so kind :)

Regards

Jocke
Given this string what do you want the results to look like?

    string txt = "item_make_list={} corpse_make_list={{[cokacola];5;5;5.6617}"
Avatar of fjocke

ASKER

Either it should replace out each INT that comes after a ; alone, or a };

So instance

;7 should be multiplied with 2 = ;14
or if its };2 multi 4 = };8

So a regex for either replacing only numbers that comes after a ; or };
Actually it would be the best if it could check wether its between two { } brackets aswell.
 
So if I understand you so far if an integer value follows a semicolon such as ;7 you always want to multiply the value by 2 and replace the value 7 in this case with the value 14 in the string.

If an integer value follows a right curly bracket followed by a semicolon such as };2 you always want to multiply the value by 4 and replace the value 2 in this case with the value 8 in the string.

All other integers do not get modified.

How about float values such as this from your example string, "{[whiskey];5;5;1.94174}", does the value, ;1.94174, get modified? If so how?

To your last statement, "Actually it would be the best if it could check wether its between two { } brackets aswell.", if it is between to { } such as in this case, "{[whiskey];5;5;1.94174}", what needs to be done?

In order to write a regex pattern I need to know the exact patterns to look for and what to do with them when they are found.

Avatar of fjocke

ASKER

npc_begin      warrior      20021      [gravel]      level=14      acquire_exp_rate=12.726      acquire_sp=95      unsowing=0      clan={-1}      ignore_clan_list={}      clan_help_range=300      slot_chest=[]      slot_rhand=[]      slot_lhand=[]      shield_defense_rate=0      shield_defense=0      skill_list={@s_gender_spoke}      npc_ai={[gravel];{[AfterShave]=100};{[AfterShave1]=100};{[AfterShave2]=100}}      category={}      race=animal      sex=male      undying=0      can_be_attacked=1      corpse_time=7      no_sleep_mode=0      agro_range=1000      ground_high={110;0;0}      ground_low={40;0;0}      exp=191455      org_hp=230.38548      org_hp_regen=2.5      org_mp=140.88      org_mp_regen=1.2      collision_radius={21;21}      collision_height={40;40}      str=40      int=21      dex=30      wit=20      con=43      men=10      base_attack_type=sword      base_attack_range=40      base_damage_range={0;0;80;120}      base_rand_dam=30      base_physical_attack=29.971106      base_critical=4      physical_hit_modify=4.75      base_attack_speed=253      base_reuse_delay=0      base_magic_attack=18.6058      base_defend=64.6198090909091      base_magic_defend=52.01457      physical_avoid_modify=0      soulshot_count=0      spiritshot_count=0      hit_time_factor=0.34      item_make_list={}      corpse_make_list={{[beercan];1;1;8.194};{[water_bottle];1;1;71.8975};{[stick_of_doom];1;1;8.194}}      additional_make_list={}      additional_make_multi_list={{{{[icecream];570;840;100}};70};{{{[banana];1;1;7.9838};{[apple_scrutt];1;1;84.0323};{[lolipop];1;1;7.9839}};1.016};{{{[mort];5;5;3.84422};{[sail];5;5;3.84422};{[pillow];1;1;18.8442};{[carbox];1;1;42.7136}};85.6295}}      hp_increase=0      mp_increase=0      safe_height=100      npc_end      

This is a ful length string.
There are sevral tousends of this line with diffrent values.
So since there are more values that starts with a ;
we'll first have to notice wether its in between corpse_make_list={} or additional_make_list={} or additional_make_multi_list={}

if it is, it should multiply or divide the the number chosen for instance, i might just want to mulitply the
70 in {{{[icecream];570;840;100}};70} with two. so then i guess we have to get a regex that takes out the number that has a }; before it for that to happend. Sometime i might have to only change the values ;570;840;100 in {{{[icecream];570;840;100}};70} and hence somehow take out only those values and multiply or divide them, does this make more sense to you?
We need to set up the rules:
The only values to be modified are those values that are in one of the following three markers:
    A)  corpse_make_list={}
    B)  additional_make_list={}
    C)  additional_make_multi_list={}

    For example: corpse_make_list={{[cokacola];5;5;5.6617};

Questions:
1. In the example I gave above how do you determine where the end of the marker? For example the sample starts with this corpse_make_list={{[ and I selected the first }; as its end, is that correct?
2. Inside the marker there are multiple values. How do you determine which value will be modified?
3. You state that the, "if it is, it should multiply or divide the the number chosen", So how do you determine to multiply or divide?
Avatar of fjocke

ASKER

1. Yes, the coprise_make_list={ will always end with a }
2. Im not really sure, but i guess id need to be able to modify both.
[cokacola];5;5;5.6617
Here it would be like this:
First ;5, Min chance for cocacola to drop as item
Sencond ;5, max change for cocacola to drop as item
Third ; the chance for this specific item to drop at all.

So what we could do i guess is to count the number of ; in between { }
And if i set 1 in the input counter, it will for instance multiply the first 5 with a chosen value.
If i specify 3 in the input counter (which counts ;) it will take 5.6617 and multiply it with a chosen value.

3. I just want to pick that out for myself, what we have now is what i want, just want to specify if  i want to multiply the regexed integer with a chosen value, OR i will just change so that i divide it.
Its just userinputed and the code you made this far is exactly as how i want it, just comment out if i want divide instead of multiply.

Hi fjocke;

The regex pattern to modify the data is in the posted sample code below. You will need to modify the event handler DivideMultiplyValue to modify the data to meet your needs. Note that the event handler signature can not be modified to send additional parameters. Any values you need to pass into it must be done before calling the Regex.Replace function as I did with the value of multDivBy.

Fernando
        private void button1_Click(object sender, EventArgs e)
        {
            // Sample Data
            string txt = "npc_begin      warrior      20021      [gravel]      level=14      acquire_exp_rate=12.726      acquire_sp=95      unsowing=0      clan={-1}      ignore_clan_list={}      clan_help_range=300      slot_chest=[]      slot_rhand=[]      slot_lhand=[]      shield_defense_rate=0      shield_defense=0      skill_list={@s_gender_spoke}      npc_ai={[gravel];{[AfterShave]=100};{[AfterShave1]=100};{[AfterShave2]=100}}      category={}      race=animal      sex=male      undying=0      can_be_attacked=1      corpse_time=7      no_sleep_mode=0      agro_range=1000      ground_high={110;0;0}      ground_low={40;0;0}      exp=191455      org_hp=230.38548      org_hp_regen=2.5      org_mp=140.88      org_mp_regen=1.2      collision_radius={21;21}      collision_height={40;40}      str=40      int=21      dex=30      wit=20      con=43      men=10      base_attack_type=sword      base_attack_range=40      base_damage_range={0;0;80;120}      base_rand_dam=30      base_physical_attack=29.971106      base_critical=4      physical_hit_modify=4.75      base_attack_speed=253      base_reuse_delay=0      base_magic_attack=18.6058      base_defend=64.6198090909091      base_magic_defend=52.01457      physical_avoid_modify=0      soulshot_count=0      spiritshot_count=0      hit_time_factor=0.34      item_make_list={}      corpse_make_list={{[beercan];1;1;8.194};{[water_bottle];1;1;71.8975};{[stick_of_doom];1;1;8.194}}      additional_make_list={}      additional_make_multi_list={{{{[icecream];570;840;100}};70};{{{[banana];1;1;7.9838};{[apple_scrutt];1;1;84.0323};{[lolipop];1;1;7.9839}};1.016};{{{[mort];5;5;3.84422};{[sail];5;5;3.84422};{[pillow];1;1;18.8442};{[carbox];1;1;42.7136}};85.6295}}      hp_increase=0      mp_increase=0      safe_height=100      npc_end";
            // Regex pattern
            string pattern = @"((?:(corpse_make_list=\{|additional_make_multi_list=\{|additional_make_list=\{)((?=[^}]).*?)(?:;(\d+\.?\d*?))+}))";
            // Create the Regex Object with the above pattern
            Regex regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            // Test value to do the multiply or divide on the data
            multDivBy = 5; // Divide or Multiply values by this number
            // Replace the data in the string with the new values returned from Regex
            string result = regex.Replace(txt, new MatchEvaluator(DivideMultiplyValue));
            //listBox2.Items.Add(result);
            textBox1.Text = result;
 
        }
 
        // Define the test value to do the multiply or divide on the data
        private int multDivBy;
 
        // Regex calls this event handler to modify the data and send the replacement string back
        private string DivideMultiplyValue(Match m)
        {
            // The following string has the value of
            // corpse_make_list=, additional_make_list=, or additional_make_multi_list=
            String name = m.Groups[2].Value;
            // The characters between ={ and the first digit
            String chars = m.Groups[3].Value;
            // The next three string values
            String value1 = m.Groups[4].Captures[0].Value;
            String value2 = m.Groups[4].Captures[1].Value;
            String value3 = m.Groups[4].Captures[2].Value;
            String mod1 = String.Empty;
            String mod2 = String.Empty;
            String mod3 = String.Empty;
            // Return this string to regex to replace the string sent into this function
            String replaceWith = String.Empty;
 
            // First Value
            if (value1.Contains("."))
            {
                // It is a float
                double dblValue = Convert.ToDouble(value1);
                // Divide or Multiply dblValue here
                //dblValue *= multDivBy;
                dblValue /= multDivBy;
                mod1 = dblValue.ToString();
            }
            else
            {
                // It is an integer
                int intValue = Convert.ToInt32(value1);
                // Divide or Multiply dblValue here
                //intValue *= multDivBy;
                intValue /= multDivBy;
                mod1 = intValue.ToString();
            }
            // Second Value
            if (value2.Contains("."))
            {
                // It is a float
                double dblValue = Convert.ToDouble(value2);
                // Divide or Multiply dblValue here
                //dblValue *= multDivBy;
                dblValue /= multDivBy;
                mod2 = dblValue.ToString();
            }
            else
            {
                // It is an integer
                int intValue = Convert.ToInt32(value2);
                // Divide or Multiply dblValue here
                //intValue *= multDivBy;
                intValue /= multDivBy;
                mod2 = intValue.ToString();
            }
            // Third Value
            if (value3.Contains("."))
            {
                // It is a float
                double dblValue = Convert.ToDouble(value3);
                // Divide or Multiply dblValue here
                //dblValue *= multDivBy;
                dblValue /= multDivBy;
                mod3 = dblValue.ToString();
            }
            else
            {
                // It is an integer
                int intValue = Convert.ToInt32(value3);
                // Divide or Multiply dblValue here
                //intValue *= multDivBy;
                intValue /= multDivBy;
                mod3 = intValue.ToString();
            }
 
            replaceWith = name + chars + ";" + mod1 + ";" + mod2 + ";" + mod3 + "}";
 
            return replaceWith;
        }

Open in new window

Avatar of fjocke

ASKER

Im trying to fix an exception getting thrown at me.
Saying "Input string was not in correct format" im using VS 2005 Pro.

It gets thrown at:

            if (value3.Contains("."))
            {
                // It is a float
                double dblValue = Convert.ToDouble(value3); <-- HERE
                // Divide or Multiply dblValue here
                //dblValue *= multDivBy;
                dblValue /= multDivBy;
                mod3 = dblValue.ToString();
            }
            else

Im not certain why that only happens there? >>

Avatar of fjocke

ASKER

Allright i solved that with a:
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");

The regex is nice, however it seems to be only working on the first selection in the items list, when i say that i mean:

Orginal string:
item_make_list={}      corpse_make_list={{[beercan];1;1;8.194};{[water_bottle];1;1;71.8975};{[stick_of_doom];1;1;8.194}}      additional_make_list={}      additional_make_multi_list={{{{[icecream];570;840;100}};70};{{{[banana];1;1;7.9838};{[apple_scrutt];1;1;84.0323};{[lolipop];1;1;7.9839}};1.016};{{{[mort];5;5;3.84422};{[sail];5;5;3.84422};{[pillow];1;1;18.8442};{[carbox];1;1;42.7136}};85.6295}}

If you compare it to our current result:

 item_make_list={}      corpse_make_list={{[beercan];2;2;16.388};{[water_bottle];1;1;71.8975};{[stick_of_doom];1;1;8.194}}      additional_make_list={}      additional_make_multi_list={{{{[icecream];1140;1680;200}};70};{{{[banana];1;1;7.9838};{[apple_scrutt];1;1;84.0323};{[lolipop];1;1;7.9839}};1.016};{{{[mort];5;5;3.84422};{[sail];5;5;3.84422};{[pillow];1;1;18.8442};{[carbox];1;1;42.7136}};85.6295}}

you see only the first instance after each and every new coprse_make_list or item_make_ist or additiional_make_multi_list gets (in this case multiplied by two) We want this to happen on every item.

If you know a good way test or get a good regexp up running im not shy to try look at it myself.
If you have a good way to test it and build it, please let me know.

You've been very helpful this far, feel free to walk away :)
I had asked you a couple of post back the question:

The only values to be modified are those values that are in one of the following three markers:
    A)  corpse_make_list={}
    B)  additional_make_list={}
    C)  additional_make_multi_list={}

because you had stated that, "we'll first have to notice wether its in between corpse_make_list={} or additional_make_list={} or additional_make_multi_list={}".

In order to write a Regex expression the rules must be identified to know what exactly needs to be matched so that a pattern can be developed for that specific pattern. The the first thing that needs to be done is to identify all the objects that could ever be in the string that needs to be match. From there you can start generalizing the objects so that a pattern can be developed.

The main site that I use for regular expressions is  http://regexlib.com/RETester.aspx . As far as downloadable software have a look here, I have tried and used the first three.

The Regulator
http://sourceforge.net/projects/regulator/

Expresso 3.0
http://www.ultrapico.com/Expresso.htm

Regular Expression Designer
http://www.radsoftware.com.au/regexdesigner/

Regex Tester and Debugger
http://www.regexbuddy.com/test.html