Search code examples
regexnotepad++non-greedy

Non-greedy regex not working like I would like (Notepad++ 8.1.1)


I am using Noteapd++ v8.1.1 on Windows 10 to edit a save file from the game Rimworld in order to change the position of items on the map.

For example, I want to move all the "Building" and "Building_something" (and not the other things) from y=104 to y=103 in a list of different items (here, the coordinates are in the form (x, 0, y), I simplified the code a bit and added line numbers):

58  <thing Class="Plant">
59      <def>Plant_TreeOak</def>
60      <id>Plant_TreeOak41339</id>
61      <pos>(100, 0, 105)</pos>
62   </thing>
63   <thing Class="Building">
64      <def>Wall</def>
65      <id>Wall28005</id>  
66      <pos>(101, 0, 105)</pos>
68   </thing>
69   <thing Class="Building">
70      <def>Wall</def>
71      <id>Wall29667</id>
72      <pos>(103, 0, 105)</pos>
74   </thing>
75   <thing Class="Building">
76      <def>Wall</def>
77      <id>Wall28005</id>
78      <pos>(101, 0, 104)</pos>
80   </thing>
81   <thing Class="Building_Door">
82      <def>Door</def>
83      <id>Door642106</id>
84      <pos>(102, 0, 104)</pos>
86   </thing>
87   <thing Class="Building">
88      <def>Wall</def>
89      <id>Wall29667</id>
90      <pos>(103, 0, 104)</pos>
92   </thing>
93   <thing Class="Plant">
94      <def>Plant_Grass</def>
95      <id>Plant_Grass203219</id>
96      <pos>(104, 0, 104)</pos>
97   </thing>

(here, on y=105 we have an oak, a wall, nothing, a wall; and on y=104 we have a wall, a door, a wall, grass).

I try to find <thing Class="Building(.*?)104\) (singleline) and replace it with <thing Class="Building$1103\). For this example, the first match starts from line 69 and ends line 78, while I'd like it to start at line 75 (the two next matches work fine).

I tried many things and looked for accurate documentation to no avail (I can't even find what regex engine Notepad++ is using...). Actually, I think that I don't understand fully how "non-greedy" regexes work.

Please consider that English is not my mother language, so technical English is sometimes tricky for me.

Thanks for your help, and please remember that I am using Notepad++, that handles regexes a bit differently sometimes (e.g. here, the \) in the replace line to make a )).


Solution

  • You can find <thing Class="Building and then match two lines below, than grab all before the last number before a ):

    <thing Class="Building(?:_[^"]*)?">(?:\R.*){2}\R.*\(.*,\h*\K104(?=\))
    

    Replace with 103. See the regex demo.

    Details:

    • <thing Class="Building - a fixed string
    • (?:_[^"]*)? - an optional seqence of a _ char followed with zero or more chars other than a " char
    • "> - a fixed string
    • (?:\R.*){2} - two lines
    • \R - a line break sequence
    • .* - 0+ chars other than line brea chars as many as possble
    • \( - a ( char
    • .* - 0+ chars other than line brea chars as many as possble
    • ,\h* - a comma and 0+ horizontal whitespaces
    • \K - match reset operator discarding all text matched so far
    • 104 - a fixed value
    • (?=\)) - next char must be a ).

    enter image description here