Sign in to follow this  
Followers 0
RichardL

Regular Expression to select text over multi-lines

6 posts in this topic

#1 ·  Posted

Text in a file, read into var with fileread:

<>
<>
<>
<>
<
J please look
>
<>
<>
<>

Hi, 

I want  a RegExp to select around 'please', back to the previous < and forward to the next >.  I can select the line of text.  Then I add in (?s) and it selects the whole text.  I think I want to make it not greedy, (?U) , that seems to make it ungreedy after, but it still selects all the previous lines.

$sPattern = "(?s)<.*please.*>"            ; 1
$sPattern = "(?s)<(?U).*please.*>"        ; 2
$sPattern = "(?s)<(?U).*please(?U).*>"    ; 3
$sAry = StringRegExp($sHTML, $sPattern, 3)

 

Share this post


Link to post
Share on other sites



#2 ·  Posted

4 hours ago, RichardL said:

back to the previous < and forward to the next >

Literally this means : you get all, including newlines just after the < and before the >

$str = FileRead("1.txt")
$res = StringRegExpReplace($str, '(?s).*<(.*?please.*?)>.*', "$1")
Msgbox(0,"", $res)

 

Share this post


Link to post
Share on other sites

#3 ·  Posted

Mikell,  Thansks for that.  I've had a quick play with it and must finish now for today (UK 23:30) It provokes questions:

1 - the .* at each end, outside the <> - what are they doing? I don't want anything outside the <>.

2 - I'm using your pattern in StringRegExp, 3) and the selected text doesn't include the immediate <> (all the text up to those, I've added a few chars to make sure.  Why aren't the <> selected if they are in the pattern?  (This agrees with what gets replaced using your StringRegExpReplace).

Richard.

 

 

 

Share this post


Link to post
Share on other sites

#4 ·  Posted

This example allows for "please" being in first line or the last line.  And returns all of the previous line, and all of the next line of the "please" contained line, if they exist.

Note: In my example and Mikell example all the text in the "test" parameter of StringRegExpReplace() is matched with the regular expression pattern. So, the only text returned is in the "replace" parameter, which is "$1".  This is the first capture group which is referenced by the first back-reference, "$1".  The first capture group or the first back-reference is defined by the matching text that is matched after the first open bracket, traveling from left to right, and before the matching close bracket.

#cs
<>
<>
<>
<>
<
J please look
>
<>
<>
<>
#ce

;$str = FileRead("1.txt")
$str = StringRegExpReplace(FileRead(@ScriptFullPath), "^(?s).*#cs\s+(.+)\s+#ce.*$", "$1") ; Extract test string from this script.
;ConsoleWrite($str  & @CRLF)

$sFind = "please"
$res = StringRegExpReplace($str, '(?s).*?((\V*\v+)?\V*\Q' & $sFind & '\E\V*(\v+\V*)?).*', "$1")

ConsoleWrite($res & @CRLF)
MsgBox(0, "Results", $res)

 

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

9 hours ago, RichardL said:

1 - the .* at each end, outside the <> - what are they doing? I don't want anything outside the <>.

The pattern represents the whole string and the part to grab is put inside brackets (capturing group). So the whole text will be replaced by the content of this group, which is backreferenced as "$1" as Malkey explained
 

9 hours ago, RichardL said:

2 -....  Why aren't the <> selected if they are in the pattern? 

because they are outside the brackets. Just move the brackets to include < and > in the group and they will be grabbed too

$str = FileRead("1.txt")
; get the wanted part
$res = StringRegExpReplace($str, '(?s).*(<.*?please.*?>).*', "$1")
; remove included newlines
$res = StringRegExpReplace($res, '\R', "")
Msgbox(0,"", $res)

Using StringRegExp, 3 is a little different. You must then specify that the chars to be grabbed around 'please' must not be < or > by using of a negated character class

$str = FileRead("1.txt")
; using StringRegExp w/ flag 3
$res = StringRegExp($str, '(?s)<[^<]*please[^>]*>', 3)
; remove newlines
$res[0] = StringRegExpReplace($res[0], '\R', "")
Msgbox(0,"", $res[0])

Edit
Please note that there are several ways to skin this cat  :)

Edited by mikell

Share this post


Link to post
Share on other sites

#6 ·  Posted

It took me a few days to get back to this.  Your patterns worked well on the example text.  When I came to look at the actual text again, the 'not include' selection to prevent it including from the first <P needed to be a string <P, not just one char [^<].  I did some Googleing and it looked hard.  Then I realised I could limit the selection to only the immediately surrounding tags using .{1,90} instead of .* .  Not a very precise way to skin the cat but it's working.  I've learned a few things, thanks.

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
Sign in to follow this  
Followers 0

  • Similar Content

    • Robinson1
      By Robinson1
      Well the plan is to use the power of regular expressions engine of AutoIT for patching binary data.
      Something like this: StringRegExp( $BinaryData,  "(?s)\x55\x8B.."
       
      <cut> ... Okay straight to question/problem
      ... certain bytes that are in the range from 0x80 to 0xA0 won't match.
      Hmm seem to be a char encoding problem. In detail these are 27 chars: 0x80, 0x82~8C, 0x8E, 0x91~9C, 0x9E,0x9F
      Here's a small code snippet to explore / explain this problem:
      #include "StringConstants.au3" $TestData = BinaryToString("0x7E7F808182") ;Okay $match = StringRegExp( $TestData ,'\x7E' ,$STR_REGEXPARRAYFULLMATCH) ConsoleWrite('@extended = ' & @extended & ' $match = ' & $match & @CRLF) ;Okay $match = StringRegExp( $TestData ,'\x7F' ,$STR_REGEXPARRAYFULLMATCH) ConsoleWrite('@extended = ' & @extended & ' $match = ' & $match & @CRLF) ;Error no match $match = StringRegExp( $TestData ,'\x80' ,$STR_REGEXPARRAYFULLMATCH) ConsoleWrite('@extended = ' & @extended & ' $match = ' & $match & @CRLF) ;Okay $match = StringRegExp( $TestData ,'\x81' ,$STR_REGEXPARRAYFULLMATCH) ConsoleWrite('@extended = ' & @extended & ' $match = ' & $match & @CRLF) ;Error no match $match = StringRegExp( $TestData ,'\x82' ,$STR_REGEXPARRAYFULLMATCH) ConsoleWrite('@extended = ' & @extended & ' $match = ' & $match & @CRLF) ;~ output: ;~ @extended = 2 $match = ;~ @extended = 3 $match = ;~ @extended = 0 $match = 1 ;~ @extended = 5 $match = ;~ @extended = 0 $match = 1 Hmm what to do? Go back and use the 'numberstring monster' implementation or just omit that range of 'unsafe bytes'. What is the root of this problem?
      Any idea how to fix this?
       
      Update: Okay I know a byte is not a character.
      But StringRegExp operates on String and so character level.
      Okay as long as you stay at Ansi encoding and only use /x00 - /X7F in the search pattern using  StringRegExp works well to search for binary data.
      What bytes can be matched that are in the range from /X7F - /xFF is also depending on the code page.
      So this avoid to search for bytes in the range from 0x80-0xa0 only applies to Germany.
      I just change this country setting:

      to Thai and now near all bytes from /X7F - /xFF fails to match.
    • JohnNash
      By JohnNash
      I want to rename every new instance of notepad to notepad(random number)
      If I use WinSetTitle ( "notepad", "", "notepad("&$randomnumber&")" )
      this will work pretty good, because if more windows match the search entry it will take the newest. But what if this code runs, but there is no new instance of notepad. It will rename one that was already assigned a number. So I would like to check whether it is already renamed. For example by excluding titles that contain a ")".
      How do I do that. 
      Read this, but that is pretty confusing: http://stackoverflow.com/questions/406230/regular-expression-to-match-line-that-doesnt-contain-a-word?rq=1
    • Mingre
      By Mingre
      #include <Array.au3> ; Script Start - Add your code below here Local $test = "<li>One<li>Inner<li>Innermost</li></li></li>" & _ "<li>Two</li> " $loob = StringRegExp($test, '\Q<li>\E(.*?)\Q</li>\E', 3) _ArrayDisplay($loob, "How to return the One... and Two?") Hello, can somebody help me:
      (1) How can I have the regexp matched the two outermost bullets? Such that:
       
      (2) How can I match the "Innermost" bullet?
      Thanks so much.
    • mLipok
      By mLipok
      #include <Array.au3> If @Compiled Then Exit Global Enum $FUNC_OUTER, $FUNC_NAME, $FUNC_PARAM, $FUNC_INNER _Example() Func _Example() Local $sIncludeDir = StringTrimRight(@AutoItExe, StringLen('AutoIt3.exe')) & 'Include\' Local $aOuterArray = _GetFunctionsToArray($sIncludeDir & 'Color.au3') If Not @error Then For $iOuter_idx = 0 To UBound($aOuterArray) - 1 _ArrayDisplay($aOuterArray[$iOuter_idx], ($aOuterArray[$iOuter_idx])[$FUNC_NAME]) Next EndIf EndFunc ;==>_Example Func _GetFunctionsToArray($sUDF_FileFullPath) Local $sUDFContent = FileRead($sUDF_FileFullPath) Local $aResult = StringRegExp($sUDFContent, '(?is)\RFunc (.*?)\((.*?)\)\v\R(.*?)\REndFunc', $STR_REGEXPARRAYGLOBALFULLMATCH) Return SetError(@error, @extended, $aResult) EndFunc ;==>_GetFunctionsToArray  
    • mjolnirmarkiv
      By mjolnirmarkiv
      Hello,
      Have been thinking about this for a while, so decided to seek for help.
      I have the following string: "...<tag>1</tag>...<tag>2</tag>...<tag>3</tag>...", which I need to test if all text within <tag> matches certain criteria, e.g. it's a number "\d+". The trick is 1) I need the entire match to fail if only one instance of the text between <tag> doesn't match "\d+"; 2) I need the string to match if there's no <tag>.
      E.g.:
      - "...<tag>1</tag>...<tag>2</tag>...<tag>3</tag>..." matches.
      - "...<tag>a</tag>...<tag>2</tag>...<tag>3</tag>..." fails.
      - "..." matches.
      Thanks!