rossnixon

Pulling specific data into variables

24 posts in this topic

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=0
Any hints at best way to do this?

 

Share this post


Link to post
Share on other sites



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?
 

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

​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?

Share this post


Link to post
Share on other sites

#7 ·  Posted (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 by SadBunny
Tidied code

Roses are FF0000, violets are 0000FF... All my base are belong to you.

Share this post


Link to post
Share on other sites

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

#ce

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

Share this post


Link to post
Share on other sites

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! :-)

Share this post


Link to post
Share on other sites

#10 ·  Posted

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.

Share this post


Link to post
Share on other sites

#11 ·  Posted

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

Share this post


Link to post
Share on other sites

#12 ·  Posted

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.
 

Share this post


Link to post
Share on other sites

#13 ·  Posted (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 by SadBunny

Roses are FF0000, violets are 0000FF... All my base are belong to you.

Share this post


Link to post
Share on other sites

#14 ·  Posted (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 by JohnOne

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Share this post


Link to post
Share on other sites

#15 ·  Posted

rossnixon,

Run the following and look at the 2D array displayed...

#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

Share this post


Link to post
Share on other sites

#16 ·  Posted

kylomas,
Creating the 2D array using this 'ubound-division' way is often hazardous

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 &= '  (999.99999,0.1,0.2)' & @CRLF
$str &= '  (1859679.75,5861040) (3839,0) Label "Pt 3"' & @CRLF

 

Share this post


Link to post
Share on other sites

#17 ·  Posted

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)

 

Share this post


Link to post
Share on other sites

#18 ·  Posted

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)

 

Share this post


Link to post
Share on other sites

#19 ·  Posted (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 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

Share this post


Link to post
Share on other sites

#20 ·  Posted

@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

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.


Sign In Now