rossnixon Posted April 30, 2015 Posted April 30, 2015 You guys were very helpful yesterday, thanks!Here is another one. I'd like suggestions on an approach to use.No speed required for this one (small files only).Example ASCII file includes the following, always in this sequence but could have whitespace in and around them: Type "RASTER" (1858720,5861040) (0,0) Label "Pt 1", (1859679.75,5859600.25) (3839,5759) Label "Pt 2", (1859679.75,5861040) (3839,0) Label "Pt 3"First: I need to confirm the file contains the text "RASTER". I can use FileRead() and then StringInStr() for that.Second: I need to pull the first 4 numbers of the following lines into variables (for later calculations). to end up with something like A1=1858720 A2=5861040 A3=0 A4 =0 B1=1859679.75 B2=5859600.25 B3=3839 B4 5759 C1=1859679.75 C2=5861040 C3=3839 C4=0Any hints at best way to do this?
JohnOne Posted April 30, 2015 Posted April 30, 2015 Two approaches are the native StringRegExp and the standard UDF _StringBetween AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
rossnixon Posted April 30, 2015 Author Posted April 30, 2015 Thanks JohnOne.I'm trying _StringBetween, and can get my first two numbers out, but I have to use my first set of string delimiters "(" and "," again. This picks up my first number again.What can I do? Perhaps find a way to record where I'm up to in the $text and trim off what I've finished with?
SadBunny Posted May 1, 2015 Posted May 1, 2015 StringRegExp can be very useful here as you can make it return an array of substrings that fir a certain pattern, like \(.*?\) for every substring that matches "parenthesis open, everything to the next parenthesis close, parenthesis close". Then you loop through the returned array and pick out what you need. You can make the pattern more specific for more specific results, or you can use stringbetween for every result, or another stringregexp to divide a result up even further... Roses are FF0000, violets are 0000FF... All my base are belong to you.
JohnOne Posted May 1, 2015 Posted May 1, 2015 Thanks JohnOne.I'm trying _StringBetween, and can get my first two numbers out, but I have to use my first set of string delimiters "(" and "," again. This picks up my first number again.What can I do? Perhaps find a way to record where I'm up to in the $text and trim off what I've finished with? The function should return an array of all values, I'm not sure I'm understanding your issue.Put a code together to show what you're doing and to demonstrate the results, and what you expect/want from it. AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
rossnixon Posted May 1, 2015 Author Posted May 1, 2015 The function should return an array of all values, I'm not sure I'm understanding your issue.Put a code together to show what you're doing and to demonstrate the results, and what you expect/want from it.$A = _StringBetween($text,"(",",") $A1 = $A[0] $A = _StringBetween($text,",",")") $A2 = $A[0] $A = _StringBetween($text,"(",",") ; oops same as 1st delimiters $A3 = $A[0]I'm getting $A1=1858720 and $A2=5861040, but $A3=1858720 again. I was hoping it would search further in the $text (whole file). Maybe I could somehow trim the $text each time?
SadBunny Posted May 1, 2015 Posted May 1, 2015 (edited) _StringBetween returns an array. You only have to call it once, then iterate through the results. Consider this example: #include <String.au3> #include <Array.au3> $s = "abc(123,456)xyz(789,000)" $matchArray = _StringBetween($s, "(", ")") For $arrayIndex = 0 To UBound($matchArray) - 1 $match = $matchArray[$arrayIndex] MsgBox(0, 0, "Found match: " & $match) $splitMatchArray = StringSplit($match, ",", $STR_NOCOUNT) _ArrayDisplay($splitMatchArray, "comma-separated substrings of " & $match & ":") Next Edited May 1, 2015 by SadBunny Tidied code Roses are FF0000, violets are 0000FF... All my base are belong to you.
kylomas Posted May 1, 2015 Posted May 1, 2015 rossnixon,One way to do it with an SRE#include <array.au3> local $str = 'Type "RASTER"' & @CRLF $str &= ' (1858720,5861040) (0,0) Label "Pt 1",' & @CRLF $str &= ' (1859679.75,5859600.25) (3839,5759) Label "Pt 2",' & @CRLF $str &= ' (1859679.75,5861040) (3839,0) Label "Pt 3"' local $aResult = stringregexp($str,'(?:\(|\,)(\d+(?:\.\d+)?)',$STR_REGEXPARRAYGLOBALMATCH) if @ERROR then consolewrite('No matches' & @LF) else _arraydisplay($aResult) endif #cs Explanation of SRE (?: start non capturing group \(|\, find an open parentheses or a comma (do not caputure because it is part of the non capturing group) ) close non capturing group ( start capturing group \d+ capture strings of 1 or more digits (?: start non capturing group (sub group of capturing group) \.\d+ match a "." followed by one or more digits )? this group may or may not exist ) close capturing group $STR_REGEXPARRAYGLOBALMATCH - return an array of global (all) matches #cekylomas 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
rossnixon Posted May 1, 2015 Author Posted May 1, 2015 Thanks SadBunny, that was a useful example. I got there in the end, but I won't post my code so as not to embarrass myself! :-)
SadBunny Posted May 1, 2015 Posted May 1, 2015 I won't post my code so as not to embarrass myself! :-)Wrong. You should. No one will laugh at you for bad code if you are looking for suggestions to improve it. Share, by all means! Maybe the forumers will have useful tips to improve. Roses are FF0000, violets are 0000FF... All my base are belong to you.
kylomas Posted May 1, 2015 Posted May 1, 2015 or learn something... 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
rossnixon Posted May 1, 2015 Author Posted May 1, 2015 Yeah OK.; Look for all (,) pairs in the text $matchArray = _StringBetween($text, "(", ")") ; all pairs are now in an array ; first line $match1 = $matchArray[0] $splitMatchArray = StringSplit($match1, ",", $STR_NOCOUNT) $A1=$splitMatchArray[0] $A2=$splitMatchArray[1] $match2 = $matchArray[1] $splitMatchArray = StringSplit($match2, ",", $STR_NOCOUNT) $A3=$splitMatchArray[0] $A4=$splitMatchArray[1] ; second line $match3 = $matchArray[2] $splitMatchArray = StringSplit($match3, ",", $STR_NOCOUNT) $B1=$splitMatchArray[0] $B2=$splitMatchArray[1] $match4 = $matchArray[3] $splitMatchArray = StringSplit($match4, ",", $STR_NOCOUNT) $B3=$splitMatchArray[0] $B4=$splitMatchArray[1] ; third line $match5 = $matchArray[4] $splitMatchArray = StringSplit($match5, ",", $STR_NOCOUNT) $C1=$splitMatchArray[0] $C2=$splitMatchArray[1] $match6 = $matchArray[5] $splitMatchArray = StringSplit($match6, ",", $STR_NOCOUNT) $C3=$splitMatchArray[0] $C4=$splitMatchArray[1]I know I could have used nested FOR NEXT loops for this, but I would have had to use more complex variables(arrays) to store each number, then copied them into simpler variable names.
SadBunny Posted May 1, 2015 Posted May 1, 2015 (edited) Just to be sure... Do you want feedback or advice on your approach? (Because if so, then I would say that in my opinion, arrays are actually much less complex than all these separate variables Especially if you want your script to be more easily troubleshootable -is that a word?-, easier to upgrade if you need more from it later or change the input data, etc.. ) Edited May 1, 2015 by SadBunny Roses are FF0000, violets are 0000FF... All my base are belong to you.
JohnOne Posted May 1, 2015 Posted May 1, 2015 (edited) I know I could have used nested FOR NEXT loops for this, but I would have had to use more complex variables(arrays) to store each number, then copied them into simpler variable names.Maybe you are unaware that you can use directly, and alter array elements directly, but at the very least, if don't want a loop, you should turn repetitive code in to functions.#include <String.au3> Local $A1, $A2, $A3, $A4, $B1, $B2, $B3, $B4, $C1, $C2, $C3, $C4 local $str = 'Type "RASTER"' & @CRLF $str &= ' (1858720,5861040) (0,0) Label "Pt 1",' & @CRLF $str &= ' (1859679.75,5859600.25) (3839,5759) Label "Pt 2",' & @CRLF $str &= ' (1859679.75,5861040) (3839,0) Label "Pt 3"' ; Look for all (,) pairs in the text $matchArray = _StringBetween($str, "(", ")") ; all pairs are now in an array ; first line _Split($matchArray[0], $A1, $A2) _Split($matchArray[1], $A3, $A4) ; second line _Split($matchArray[2], $B1, $B2) _Split($matchArray[3], $B3, $B4) ; third line _Split($matchArray[4], $C1, $C2) _Split($matchArray[5], $C3, $C4) Func _Split(ByRef $string, ByRef $s1, ByRef $s2) Local $splitMatchArray = StringSplit($string, ",", 2) $s1 = $splitMatchArray[0] $s2 = $splitMatchArray[1] EndFunc ;==>_Split Edited May 1, 2015 by JohnOne AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans.
kylomas Posted May 1, 2015 Posted May 1, 2015 rossnixon,Run the following and look at the 2D array displayed...expandcollapse popup#include <array.au3> Local $str = 'Type "RASTER"' & @CRLF $str &= ' (1858720,5861040) (0,0) Label "Pt 1",' & @CRLF $str &= ' (1859679.75,5859600.25) (3839,5759) Label "Pt 2",' & @CRLF $str &= ' (1859679.75,5861040) (3839,0) Label "Pt 3"' & @CRLF $str &= ' (999.99999,0.1,0.2)' Local $aResult = StringRegExp($str, '(?:\(|\,)(\d+(?:\.\d+)?)', $STR_REGEXPARRAYGLOBALMATCH) If @error Then exit msgbox(16,'ERROR','No Matches') #cs Explanation of SRE (?: start non capturing group \(|\, find an open parentheses or a comma (do not caputure because it is part of the non capturing group) ) close non capturing group ( start capturing group \d+ capture strings of 1 or more digits (?: start non capturing group (sub group of capturing group) \.\d+ match a "." followed by one or more digits )? this group may or may not exist ) close capturing group $STR_REGEXPARRAYGLOBALMATCH - return an array of global (all) matches #ce ; format into 2D array - 1 row for each line Local $a2D[UBound($aResult) / 4+1][4] Local $rowidx = 0, $colidx = 0 For $1 = 0 To UBound($aResult) - 1 $a2D[$rowidx][$colidx] = $aResult[$1] If $colidx = 3 Then $rowidx += 1 $colidx = 0 Else $colidx += 1 EndIf Next _ArrayDisplay($a2D)Now lets say that you want to process the 2ND entry on the 3RD line. You would reference the array as $a2D[2][1] (arrays are zero offset - "2" is the row and "1" is the column). This seems a lot more straightforward than populating a bunch of sequentially named variables. The real power of using an array is the ability to loop through them.The Wiki has excellent tutorials about arrays and other AutoIt subjects.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
mikell Posted May 1, 2015 Posted May 1, 2015 kylomas,Creating the 2D array using this 'ubound-division' way is often hazardousLocal $str = 'Type "RASTER"' & @CRLF $str &= ' (1858720,5861040) (0,0) Label "Pt 1",' & @CRLF $str &= ' (1859679.75,5859600.25) (3839,5759) Label "Pt 2",' & @CRLF $str &= ' (999.99999,0.1,0.2)' & @CRLF $str &= ' (1859679.75,5861040) (3839,0) Label "Pt 3"' & @CRLF
jguinch Posted May 1, 2015 Posted May 1, 2015 To have a non-hazardous result, you can use an expression witch captures exacty what you want.In this case, you have to declare 4 capturing groups :local $aResult = stringregexp($str,'\((\d+(?:\.\d+)?),(\d+(?:\.\d+)?)\)\h*\((\d+(?:\.\d+)?),(\d+(?:\.\d+)?)\) *',$STR_REGEXPARRAYGLOBALMATCH) $aResult = _Array1DTo2D($aResult, 4) ; http://www.autoitscript.com/forum/topic/165600-_array1dto2d/ _ArrayDisplay($aResult) Spoiler Network configuration UDF, _DirGetSizeByExtension, _UninstallList Firefox ConfigurationArray multi-dimensions, Printer Management UDF
mikell Posted May 1, 2015 Posted May 1, 2015 You can also manage to get rid of the non valid lines#include <array.au3> Local $str = 'Type "RASTER"' & @CRLF $str &= ' (1858720,5861040) (0,0) Label "Pt 1",' & @CRLF $str &= ' ' & @CRLF $str &= ' (1859679.75,5859600.25) (3839,5759) Label "Pt 2",' & @CRLF $str &= ' (999.99999,0.1,0.2)' & @CRLF $str &= ' (1859679.75,5861040) (3839,0) Label "Pt 3"' Local $rows = StringRegExp($str, '(?m)\(.*?\)\h*\(.*?\)', 3) ;_ArrayDisplay($rows) Local $a2D[UBound($rows)][4] For $i = 0 to UBound($rows) - 1 $cols = StringRegExp($rows[$i], '[\d.]+', 3) For $j = 0 to UBound($cols) - 1 $a2D[$i][$j] = $cols[$j] Next Next _ArrayDisplay($a2D)
kylomas Posted May 1, 2015 Posted May 1, 2015 (edited) @jguinch, mikell,Thanks, I thought my attempt at an SRE might bring out REAL SRE writers.Not sure what you mean by "non valid lines" though. I intentionally added a short line to demonstrate the method, however, your code is certainly more bullet proof.kylomas Edited May 1, 2015 by kylomas clarification 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
kylomas Posted May 1, 2015 Posted May 1, 2015 @jquinch - Your SRE and my SRE yield exactly the same result. What am I missing? 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
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