-1

I'm writing a regex to to capture all text in a multi line file between @id=1 and #. When I say # I mean the first solitary # at the start of a line with an optional space afterwards. I'm programming in dart. The regex I came up with is as follows:

/^@id ?= ?1$(.*)^# ?$/gms

I'm getting some strange results. On RegExr.com the regex has a match, but it does not stop at the first # ?$. In dart, I get no match at all. Here is my dart code

  var matchContents =
      RegExp(r'^@id ?= ?1$(.*)^# ?$', multiLine: true, dotAll: true);
  var testString = '''
      alskdfkldsfjd
      # thekt nect
      @id=2
      akdfjdkf
      adlksfj
      @id=1
      adksfklasdjf // This line should be captured
      asdlkfjdkfj  // And this one
      @id=3        // this one
      dkfjadklfja  // And this one
      # 
      kdsalfjaslkdf
      #
      ''';
  print(matchContents.hasMatch(testString)); // This checks if there is any match (it's currently false)

Why isn't this working and how do I fix it?

ayNONE
  • 125
  • 1
  • 2
  • 10
  • 1
    You may use this regex in `MULTILINE` mode: `^@id *= *1$[^#]*#`. No need to use `dotall` here since we're using negated character class. – anubhava Nov 11 '20 at 16:53
  • 1
    `.*` is greedy, just use the lazy `.*?` – Wiktor Stribiżew Nov 11 '20 at 17:12
  • @WiktorStribiżew that fixed my problem on RegExr but not in dart. – ayNONE Nov 11 '20 at 17:15
  • 2
    It works in Dart. You just declared the stirng with indentations and it turns out **you tested against another string in Dart and online**. If the string is defined like `var testString = "alskdfkldsfjd\n# thekt nect\n@id=2\nakdfjdkf\nadlksfj\n@id=1\nadksfklasdjf // This line should be captured\nasdlkfjdkfj // And this one\n@id=3 // this one\ndkfjadklfja // And this one\n#kdsalfjaslkdf\n#";` it works. `print(testString);` and you will see. So, **the only real issue** is the **use of the greedy quantifier**. – Wiktor Stribiżew Nov 11 '20 at 17:19
  • @WiktorStribiżew well you just taught me something new about multiline strings. – ayNONE Nov 11 '20 at 17:22
  • 1
    Always make sure you test against one and the same test, both online and in code. – Wiktor Stribiżew Nov 11 '20 at 17:23

1 Answers1

0

Instead of using dotall mode you can leverage negated character class to match across line breaks and simplify your regex.

This regex may work for you in MULTILINE mode:

^@id *= *1[\r\n]+((?:[^#]*#)+?)(?<=^#)$

RegEx Demo

RegEx Details:

  • ^@id *= *1: From a start of line match @id=1 allowing optional spaces around =
  • [\r\n]+: Match 1+ newline characters
  • ([^#]*): Match 0 more characters that are not # using negated character class [^#]
  • #: Match a #
  • (?<=^#)$: Stop match when we have # all by itself on a separate line
anubhava
  • 664,788
  • 59
  • 469
  • 547
  • That almost does what I need but this stops at any `#` even at the end of a line or multiple `#`s in a row. What I need is a regex that stops at a `#` that is at the beginning of a line and completely alone on that line except for an optional space. – ayNONE Nov 11 '20 at 17:09
  • please try my updated answer, which matches a `#` in a separate line. – anubhava Nov 11 '20 at 17:19
  • 1
    As it turns out, the reason why it didn't work in dart is because my string was indented. Thanks, your solution works too. – ayNONE Nov 11 '20 at 17:26
  • jfyi with `dotall` it would be `^@id *= *1[\r\n]+(.*?)^#$` but that will be more inefficient – anubhava Nov 11 '20 at 17:29