Baraoic Posted April 23, 2013 Author Posted April 23, 2013 Look for one of the operators or beginning of line kylomas Oh I coulda used that a while back, thanks. Anyways, couldn't the regex be $sre = '(?<=[*/+-]|^)[-]?[d.]+[*/][-]?[d.]+' as I don't see what the 2nd (?<=[*/+-]) is needed for as the input will always be in the format [*|/|+|-][-?][number][*|/][-?][number] so the 2nd number can't be proceeded by add and we already account for the negative and multiply and divide. Also why is the negative from [-]?[d.] in brackets? Also I like your way more as it looks like I can skip the whole 2nd regex trying to grab just the numbers. So I have made those changes I just mentioned and updated the functions so they are now this: While StringRegExp($sLine, "\*|/") $aRegex = StringRegExp($sLine, "(?<=[\*\/\+-]|^)(-?[\d\.]+)([\*/])(-?[\d\.]+)", 1) If StringInStr($aRegex[1], "*") Then $sLine = StringReplace($sLine, $aRegex[0] & $aRegex[1] & $aRegex[2], _GMP_MulFloat($aRegex[0], $aRegex[2], $iDigits)) Else $sLine = StringReplace($sLine, $aRegex[0] & $aRegex[1] & $aRegex[2], _GMP_DivFloat($aRegex[0], $aRegex[2], $iDigits)) EndIf WEnd While StringRegExp($sLine, "[\d\.]+\+-?[\d\.]+|[\d\.]+-+[\d\.]+") $aRegex = StringRegExp($sLine, "(-?[\d\.]+)([\+-])(-?[\d\.]+)", 1) If StringInStr($aRegex[1], "+") Then $sLine = StringReplace($sLine, $aRegex[0] & $aRegex[1] & $aRegex[2], _GMP_AddFloat($aRegex[0], $aRegex[2], $iDigits)) Else $sLine = StringReplace($sLine, $aRegex[0] & $aRegex[1] & $aRegex[2], _GMP_SubFloat($aRegex[0], $aRegex[2], $iDigits)) EndIf WEnd Now the question is how do you apply the same logic to the power of function. The issue is it can contain mutiple level power of such as 5+3-3^2^4-2 would need to capture 3^2^4. I am not sure how to repeat the 2nd number capture.
kylomas Posted April 23, 2013 Posted April 23, 2013 Omnichan, Also why is the negative from [-]?[d.] in brackets? It probably does'nt need to be bracketed, when I first started that piece I thought that I might look for more than just "-". Anyways, couldn't the regex be $sre = '(?<=[*/+-]|^)[-]?[d.]+[*/][-]?[d.]+' as I don't see what the 2nd (?<=[*/+-]) is needed for as the input will always be in the format [*|/|+|-][-?][number][*|/][-?][number] so the 2nd number can't be proceeded by add and we already account for the negative and multiply and divide. To keep negation of right side of operation, if present, at least I think that's how it works. I'm sure that there are many ways to do this and suspect that you know way more about SRE than I do. As I alluded to earlier, this shit makes my head hurt but I'm stubborn and have a hard time accepting that I can't do something... Now the question is how do you apply the same logic to the power of function. The issue is it can contain mutiple level power of such as 5+3-3^2^4-2 would need to capture 3^2^4. I am not sure how to repeat the 2nd number capture. Yes, and I'm wondering how you are going to enforce order of precedence. Maybe one of the heavy hitters has some thoughts. kylomas Forum Rules Procedure for posting code "I like pigs. Dogs look up to us. Cats look down on us. Pigs treat us as equals." - Sir Winston Churchill
Baraoic Posted April 23, 2013 Author Posted April 23, 2013 Yes, and I'm wondering how you are going to enforce order of precedence. Maybe one of the heavy hitters has some thoughts. kylomas I am very much a novice at regex, as my examples have shown they aren't very good and didn't even think of the "lookbehind" you did. Now I assume you are talking about muti level, power of, order of operations? That I am not sure yet, at first I was doing something like this: While StringInStr($sLine, "^") $aRegex = StringRegExp($sLine, "(?:\-)(-[\d\.]+[\^\-\.\d]+)|(?:\+)(-[\d\.]+[\^\-\.\d]+)|[\d\.]+[\^\-\.\d]+", 1) $aRegex2 = StringRegExp($aRegex[0], "(-?[\d\.]+)+", 3) $x = UBound($aRegex2) - 3 $aRes = _GMP_PowFloat($aRegex2[$x + 1], $aRegex2[$x + 2], $iDigits) While $x > -1 $aRes = _GMP_PowFloat($aRegex2[$x], $aRes, $iDigits) $x -= 1 WEnd $sLine = StringReplace($sLine, $aRegex[0], $aRes) WEnd Which works, but doesn't account for the example in the previous post "5+3-3^2^4-2" as it's grabbing the 3- beginning and -2 ending. I will just have to think about it some more.
PhoenixXL Posted April 24, 2013 Posted April 24, 2013 (edited) Check this outexpandcollapse popup#include <Array.au3> $sline = "5+3+-3^2^4-2*15*225/9+92" ;Value is 5911 MsgBox(64, "Calculation Return", Calc_ThroughSRE($sline)) ;Priority ;~ ^ ;~ * / ;~ + - ;Note that I'm not having the GMP UDF therefore I'm just parsing the numbers and finding the value with EXECUTE you should use your GMP functions in that case for arbitrary-precision Func Calc_ThroughSRE($sfString) Local $asOperator[5] = ["\^", "*", "/", "+", "-"] ;I'm assuming the numbers are on the basis of priority, i.e. brackets are not used to perform the operations. ;Strip any spaces $sfString = StringStripWS($sfString, 8) If StringRegExp($sfString, "[^*/+-^\d.]") Then Return SetError(1, 0, 0) ;Chars other than operators, period and digits are present! If StringRegExp($sfString, "^(?![*^/+-])", "") Then $sfString = "+" & $sfString ;Append the starting operator if not any. If StringRegExp($sfString, "[*^/+-]") = 0 Then Return SetError(2, 0, 0) ;No operators present $sfString = PlusMinus_ToSingle($sfString) Local $l For $j = 0 To 4 While StringRegExp($sfString, "(?<!^)[" & $asOperator[$j] & "]") ; $sfString_Temp = StringRegExp($sfString, "(.*?)([-+][\d.]+[" & $asOperator[$j] & "][-+]?[\d.]+)(.*)", 4) If @error Then ExitLoop $l = $sfString_Temp[0] ;Taking the first index since the full string is matched ;Here ;$l[1] is the pre part ;$l[3] is the post part ;$l[2] is the part which has to be processed ;After processing we will concatenate them ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') Before Execute : $l[2] = ' & $l[2] & @TAB & 'Operator : $asOperator[$i] = ' & $asOperator[$j] & @CRLF) ;### Debug Console $l[2] = Execute($l[2]) ;You would need to perform your respective GMP function, check $asOperator[$j] to find out which operation has to be performed If $l[2] > 0 Then $l[2] = "+" & $l[2] ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') After Execute : $l[2] = ' & $l[2] & @CRLF) ;### Debug Console $sfString = _ArrayToString($l, "", 1) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') Concatenation : $sfString = ' & $sfString & @CRLF) ;### Debug Console ;This loop has an endpoint here - it will continue again. ConsoleWrite("+Executed" & @CRLF) WEnd Next Return Number($sfString) ;Use your respective GMP function. EndFunc ;==>Calc_ThroughSRE Func PlusMinus_ToSingle($String) Do $String = StringRegExpReplace($String, "([+-])\1", "+") ; ++|-- = + Until @extended = 0 Do $String = StringRegExpReplace($String, "(\+-|-\+)", "-") ; +-|-+ = - Until @extended = 0 Return $String EndFunc ;==>PlusMinus_ToSingleUse Tide(CTRL + T from Scite) before reading the scriptLogic BehindIf there are more than two operators in sequence simplify them to oneUse priority order through array and get the number(including negative sign) preceding the highest prior(at that moment) operator and the number after that operator(including negative sign). The remainder string is stored in an array for concatenation after parsing the current number.Execute the number to get the return value, at this point you should use your respective GMP function. If the number received is positive, append it with a "+" sign.Concatenate with total array so we get the parsed number with the remainder string.Now loop through the remaining left operators and return the result.FunctionCalculates the result through SRE with stepwise methods.Supports floating point numbers.Preserves the priority order specified in the helpfile.LimitationsCannot parse if brackets are used to specify order of processing(I can add it, ask if required).Ask if you run into any problemsThumbs up if it helpedRegards Edited April 24, 2013 by PhoenixXL My code: PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners. MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.
Baraoic Posted April 24, 2013 Author Posted April 24, 2013 Check this outexpandcollapse popup#include <Array.au3> $sline = "5+3+-3^2^4-2*15*225/9+92" ;Value is 5911 MsgBox(64, "Calculation Return", Calc_ThroughSRE($sline)) ;Priority ;~ ^ ;~ * / ;~ + - ;Note that I'm not having the GMP UDF therefore I'm just parsing the numbers and finding the value with EXECUTE you should use your GMP functions in that case for arbitrary-precision Func Calc_ThroughSRE($sfString) Local $asOperator[5] = ["\^", "*", "/", "+", "-"] ;I'm assuming the numbers are on the basis of priority, i.e. brackets are not used to perform the operations. ;Strip any spaces $sfString = StringStripWS($sfString, 8) If StringRegExp($sfString, "[^*/+-^\d.]") Then Return SetError(1, 0, 0) ;Chars other than operators, period and digits are present! If StringRegExp($sfString, "^(?![*^/+-])", "") Then $sfString = "+" & $sfString ;Append the starting operator if not any. If StringRegExp($sfString, "[*^/+-]") = 0 Then Return SetError(2, 0, 0) ;No operators present $sfString = PlusMinus_ToSingle($sfString) Local $l For $j = 0 To 4 While StringRegExp($sfString, "(?<!^)[" & $asOperator[$j] & "]") ; $sfString_Temp = StringRegExp($sfString, "(.*?)([-+][\d.]+[" & $asOperator[$j] & "][-+]?[\d.]+)(.*)", 4) If @error Then ExitLoop $l = $sfString_Temp[0] ;Taking the first index since the full string is matched ;Here ;$l[1] is the pre part ;$l[3] is the post part ;$l[2] is the part which has to be processed ;After processing we will concatenate them ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') Before Execute : $l[2] = ' & $l[2] & @TAB & 'Operator : $asOperator[$i] = ' & $asOperator[$j] & @CRLF) ;### Debug Console $l[2] = Execute($l[2]) ;You would need to perform your respective GMP function, check $asOperator[$j] to find out which operation has to be performed If $l[2] > 0 Then $l[2] = "+" & $l[2] ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') After Execute : $l[2] = ' & $l[2] & @CRLF) ;### Debug Console $sfString = _ArrayToString($l, "", 1) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') Concatenation : $sfString = ' & $sfString & @CRLF) ;### Debug Console ;This loop has an endpoint here - it will continue again. ConsoleWrite("+Executed" & @CRLF) WEnd Next Return Number($sfString) ;Use your respective GMP function. EndFunc ;==>Calc_ThroughSRE Func PlusMinus_ToSingle($String) Do $String = StringRegExpReplace($String, "([+-])\1", "+") ; ++|-- = + Until @extended = 0 Do $String = StringRegExpReplace($String, "(\+-|-\+)", "-") ; +-|-+ = - Until @extended = 0 Return $String EndFunc ;==>PlusMinus_ToSingleUse Tide(CTRL + T from Scite) before reading the script Logic BehindIf there are more than two operators in sequence simplify them to oneUse priority order through array and get the number(including negative sign) preceding the highest prior(at that moment) operator and the number after that operator(including negative sign). The remainder string is stored in an array for concatenation after parsing the current number.Execute the number to get the return value, at this point you should use your respective GMP function. If the number received is positive, append it with a "+" sign.Concatenate with total array so we get the parsed number with the remainder string.Now loop through the remaining left operators and return the result.FunctionCalculates the result through SRE with stepwise methods.Supports floating point numbers.Preserves the priority order specified in the helpfile.LimitationsCannot parse if brackets are used to specify order of processing(I can add it, ask if required).Ask if you run into any problems Thumbs up if it helped Regards The problem with doing it this way is you are prioritizing multiplication above division when they should be done at the same time from left to right. This is why I designed my function to search for each occurrence of multiply or divide then do that. For example using your function with $sline = "4/7*2" will give 0.5714... when the correct answer is 1.1428... I ran into that issue when I first ported the parse function from the BigNum UDF.
BrewManNH Posted April 24, 2013 Posted April 24, 2013 Multiplicataion and division are never going to be done "at the same time" you have to prioritize one over the other because this is being done in a single thread. Normally you work from the left side to the right side. Unless you're doing this as an experiment with RegEx, you'd be better off using Execute than trying to figure out what math to perform on the string, because AutoIt already has operator precedence built in. If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag GudeHow to ask questions the smart way! I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from. Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays. - ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script. - Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label. - _FileGetProperty - Retrieve the properties of a file - SciTE Toolbar - A toolbar demo for use with the SciTE editor - GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI. - Latin Square password generator
Baraoic Posted April 24, 2013 Author Posted April 24, 2013 Multiplicataion and division are never going to be done "at the same time" you have to prioritize one over the other because this is being done in a single thread. Normally you work from the left side to the right side.Unless you're doing this as an experiment with RegEx, you'd be better off using Execute than trying to figure out what math to perform on the string, because AutoIt already has operator precedence built in.I didn't mean literally at the same time. It is quite easy to do both multiply and divide "at the same time" as I have shown in my example. I just look for the first occurrence of either multiply or divide then perform that operation. This solves the issue that I just shown that PhoenixXL's script has.While it is an interesting regex experience I do have a reason for not using execute. For example I needMod("63934815732645388818955836683141460395595539940125161372454220285063032653879109791800034", "42")which equals 28, but AutoIt returns 4.40353414171194e+078. This is just one example as I do need large precision multiplication as well, which is why I am using the GMP library and have updated the UDF for it.I also wanted to include the BigNum parse function in the GMP UDF, but it didn't work properly. So that is why I have rewritten it.If you haven't followed the thread, kylomas has already help solve the issue I was having with the multiplication/division and addition/subtraction searching regex. The only issue I have is trying to apply that to the power of part.
Baraoic Posted April 24, 2013 Author Posted April 24, 2013 Just a final update, I ended up with just something similar to what I already had for the power of regex. I couldn't figure out exactly what I wanted, but this will work. Here is the result expandcollapse popupFunc _GMP_ParseFloat($sLine, $iDigits = 128) $sLine = StringStripWS($sLine, 8) If StringInStr($sLine, "(") Then $sParStart = StringInStr($sLine, "(") $sParEnd = StringInStr($sLine, ")", 0, -1) $sParMid = StringMid($sLine, $sParStart + 1, $sParEnd - $sParStart - 1) $sParNew = _GMP_ParseFloat($sParMid, $iDigits) If StringRegExp(StringMid($sLine, $sParStart - 1, 1), "\d") Then $sParNew = "*" & $sParNew If StringRegExp(StringMid($sLine, $sParEnd + 1, 1), "\d|\.") Then $sParNew &= "*" $sLine = StringReplace($sLine, "(" & $sParMid & ")", $sParNew) EndIf While StringInStr($sLine, "^") $aRegex = StringRegExp($sLine, "(?<=[\*/\+-]|^)-?[\d\.]+\^-?[\^\d\.]+", 1) $aRegex2 = StringRegExp($aRegex[0], "-?[\d\.]+", 3) $sCount = UBound($aRegex2) - 3 $aRes = _GMP_PowFloat($aRegex2[$sCount + 1], $aRegex2[$sCount + 2], $iDigits) While $sCount > -1 $aRes = _GMP_PowFloat($aRegex2[$sCount], $aRes, $iDigits) $sCount -= 1 WEnd $sLine = StringReplace($sLine, $aRegex[0], $aRes) WEnd While StringRegExp($sLine, "\*|/") $aRegex = StringRegExp($sLine, "(?<=[\*/\+-]|^)(-?[\d\.]+)([\*/])(-?[\d\.]+)", 1) If StringInStr($aRegex[1], "*") Then $sLine = StringReplace($sLine, $aRegex[0] & $aRegex[1] & $aRegex[2], _GMP_MulFloat($aRegex[0], $aRegex[2], $iDigits)) Else $sLine = StringReplace($sLine, $aRegex[0] & $aRegex[1] & $aRegex[2], _GMP_DivFloat($aRegex[0], $aRegex[2], $iDigits)) EndIf WEnd While StringRegExp($sLine, "[\d\.]+\+-?[\d\.]+|[\d\.]+-+[\d\.]+") $aRegex = StringRegExp($sLine, "(-?[\d\.]+)([\+-])(-?[\d\.]+)", 1) If StringInStr($aRegex[1], "+") Then $sLine = StringReplace($sLine, $aRegex[0] & $aRegex[1] & $aRegex[2], _GMP_AddFloat($aRegex[0], $aRegex[2], $iDigits)) Else $sLine = StringReplace($sLine, $aRegex[0] & $aRegex[1] & $aRegex[2], _GMP_SubFloat($aRegex[0], $aRegex[2], $iDigits)) EndIf WEnd Return $sLine EndFunc ;==>_GMP_ParseFloat Thanks for all of the help.
PhoenixXL Posted April 25, 2013 Posted April 25, 2013 I just look for the first occurrence of either multiply or divide then perform that operation.Yes we can just add a or operation in the regex so that the first occurance of multiplication and division would be executed.expandcollapse popup#include <Array.au3> $sline = "4/7*2" ;Value is 5911 MsgBox(64, Execute($sline), Calc_ThroughSRE($sline)) ;Priority ;~ ^ ;~ * / ;~ + - ;Note that I'm not having the GMP UDF therefore I'm just parsing the numbers and finding the value with EXECUTE you should use your GMP functions in that case for arbitrary-precision Func Calc_ThroughSRE($sfString) Local $asOperator[4] = ["\^", "*/", "+", "-"] ;I'm assuming the numbers are on the basis of priority, i.e. brackets are not used to perform the operations. ;Strip any spaces $sfString = StringStripWS($sfString, 8) If StringRegExp($sfString, "[^*/+-^\d.]") Then Return SetError(1, 0, 0) ;Chars other than operators, period and digits are present! If StringRegExp($sfString, "^(?![*^/+-])", "") Then $sfString = "+" & $sfString ;Append the starting operator if not any. If StringRegExp($sfString, "[*^/+-]") = 0 Then Return SetError(2, 0, 0) ;No operators present $sfString = PlusMinus_ToSingle($sfString) Local $l For $j = 0 To 3 While StringRegExp($sfString, "(?<!^)[" & $asOperator[$j] & "]") ; $sfString_Temp = StringRegExp($sfString, "(.*?)([-+][\d.]+[" & $asOperator[$j] & "][-+]?[\d.]+)(.*)", 4) If @error Then ExitLoop $l = $sfString_Temp[0] ;Taking the first index since the full string is matched ;Here ;$l[1] is the pre part ;$l[3] is the post part ;$l[2] is the part which has to be processed ;After processing we will concatenate them ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') Before Execute : $l[2] = ' & $l[2] & @TAB & 'Operator : $asOperator[$i] = ' & $asOperator[$j] & @CRLF) ;### Debug Console $l[2] = Execute($l[2]) ;You would need to perform your respective GMP function, check $asOperator[$j] to find out which operation has to be performed If $l[2] > 0 Then $l[2] = "+" & $l[2] ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') After Execute : $l[2] = ' & $l[2] & @CRLF) ;### Debug Console $sfString = _ArrayToString($l, "", 1) ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') Concatenation : $sfString = ' & $sfString & @CRLF) ;### Debug Console ;This loop has an endpoint here - it will continue again. ConsoleWrite("+Executed" & @CRLF) WEnd Next Return Number($sfString) ;Use your respective GMP function. EndFunc ;==>Calc_ThroughSRE Func PlusMinus_ToSingle($String) Do $String = StringRegExpReplace($String, "([+-])\1", "+") ; ++|-- = + Until @extended = 0 Do $String = StringRegExpReplace($String, "(\+-|-\+)", "-") ; +-|-+ = - Until @extended = 0 Return $String EndFunc ;==>PlusMinus_ToSingle My code: PredictText: Predict Text of an Edit Control Like Scite. Remote Gmail: Execute your Scripts through Gmail. StringRegExp:Share and learn RegExp.Run As System: A command line wrapper around PSEXEC.exe to execute your apps scripts as System (LSA). Database: An easier approach for _SQ_LITE beginners. MathsEx: A UDF for Fractions and LCM, GCF/HCF. FloatingText: An UDF for make your text floating. Clipboard Extendor: A clipboard monitoring tool. Custom ScrollBar: Scroll Bar made with GDI+, user can use bitmaps instead. RestrictEdit_SRE: Restrict text in an Edit Control through a Regular Expression.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now