On Which Line Number Was the Regex Match Found?

前端 未结 3 713
情深已故
情深已故 2021-01-25 08:55

I would like to search a .java file using Regular Expressions and I wonder if there is a way to detect one what lines in the file the matches are found.

Fo

3条回答
  •  清歌不尽
    2021-01-25 09:43

    Possible... with Regex Trickery!

    Disclaimer: This is not meant to be a practical solution, but an illustration of a way to use an extension of a terrific regex hack. Moreover, it only works on regex engines that allow capture groups to refer to themselves. For instance, you could use it in Notepad++, as it uses the PCRE engine—but not in Java.

    Let's say your file is:

    some code
    more code
    hey, hello!
    more code
    

    At the bottom of the file, paste :1:2:3:4:5:6:7, where : is a delimiter not found in the rest of the code, and where the numbers go at least as high as the number of lines.

    Then, to get the line of the first hello, you can use:

    (?m)(?:(?:^(?:(?!hello).)*(?:\r?\n))(?=[^:]+((?(1)\1):\d+)))*.*hello(?=[^:]+((?(1)\1)+:(\d+)))
    

    The line number of the first line containing hello will be captured by Group 2.

    • In the demo, see Group 2 capture in the right pane.
    • The hack relies on a group referring to itself. In the classic @Qtax trick, this is done with (?>\1?). For diversity, I used a conditional instead.

    Explanation

    • The first part of the regex is a line skipper, which captures an increasing amount of the the line counter at the bottom to Group 1
    • The second part of the regex matches hello and captures the line number to Group 2
    • Inside the line skipper, (?:^(?:(?!hello).)*(?:\r?\n)) matches a line that doesn't contain hello.
    • Still inside the line skipper, the (?=[^:]+((?(1)\1):\d+)) lookahead gets us to the first : with [^:]+ then the outer parentheses in ((?(1)\1):\d+)) capture to Group 1... if Group 1 is set (?(1)\1) then Group 1, then, regardless, a colon and some digits. This ensures that each time the line skipper matches a line, Group 1 expands to a longer portion of :1:2:3:4:5:6:7
    • The * mataches the line skipper zero or more times
    • .*hello matches the line with hello
    • The lookahead (?=[^:]+((?(1)\1)+:(\d+))) is identical to the one in the line skipper, except that this time the digits are captured to Group 2: (\d+)
    • -

    Reference

    • Qtax trick (recently awarded an additional bounty by @AmalMurali)
    • Replace a word with the number of the line on which it is found

提交回复
热议问题