Files
Oliver Hamlet c1194ac2ec Migrate from Jekyll to Hugo
Hugo is a lot easier to work with locally (especially on Windows), and
because it's not natively supported by GitHub Pages, it gets deployed
using GitHub Actions, so it's also easier to keep the version of Hugo in
sync between local builds and deployments.

I've compared the generated _site/ and public/ folders and they look
equivalent, except that Hugo also generates a sitemap: that can be
disabled, but it's good to have.
2026-01-11 17:48:57 +00:00

1218 lines
52 KiB
HTML

---
layout: page
title: Regular Expression - Regex
weight: 3
aliases:
- Regular-Expression-Regex.html
---
<p>The purpose of this page is to provide detailed information for using Regex while editing a masterlist, as well as searching specific terms within it. Regular expressions can formally be described as follows:</p>
<blockquote cite="https://en.wikipedia.org/wiki/Regular_expression">
A regular expression (shortened as regex or regexp) is a sequence of characters that specifies a search pattern in text.
</blockquote>
<h3>General</h3>
<ul>
<li>Overview of Regular Expressions: <a href="https://www.rexegg.com/regex-quickstart.html">Quick-Start: Regex Cheat Sheet</a></li>
<li>Quickly test your Regex: <a href="https://regex101.com/">Regular Expressions 101</a></li>
</ul>
<h4>Advantages of Regex</h4>
Let's take a look at <a href="https://www.nexusmods.com/skyrimspecialedition/mods/41713/">DragonPriest Retexture</a> for a first example:
<p>The DragonPriest Retexture mod includes the two different plugins <code>AcolyteMasks.esl</code> and <code>AcolyteMasks.esp</code>. If we want to add a <code>url</code> for each plugin, we could write the masterlist entry like this:<p>
<pre><code>
- name: 'AcolyteMasks.esl'
url:
- link: 'https://www.nexusmods.com/skyrimspecialedition/mods/41713/'
name: 'DragonPriest Retexture'
- name: 'AcolyteMasks.esp'
url:
- link: 'https://www.nexusmods.com/skyrimspecialedition/mods/41713/'
name: 'DragonPriest Retexture'
</code></pre>
<p>This writing-style is a valid method to add metadata to the masterlists and it also means that searching for the plugin entry (e.g. <code>AcolyteMasks.esl</code>) is fast and easy, as it is exactly the same as the actual plugin name.</p>
<p>The downside to it is however, that these non-regex entries take up more space than their regex counterparts, as we have added the same link twice to the masterlist. In order to keep things maintainable, we often choose to make use of regular expressions such as the following one:</p>
<pre><code> - name: 'AcolyteMasks\.es(l|p)'
url:
- link: 'https://www.nexusmods.com/skyrimspecialedition/mods/41713/'
name: 'DragonPriest Retexture'
</code></pre>
<p>Three different aspects have been changed respectively added in order for this regular expression to work.</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it. This is necessary so that the period is actually recognized as such. Escaping means reducing ambiguity in a more general sense.</li>
<li>After the string <code>es</code> follows a capturing group <code>( )</code>. The content of this capturing group needs to follow what is infront of it.</li>
<li>Inside the capturing group are the letters l and p, seperated by the OR operand <code>|</code>. Both letters are valid alternatives for our regex.</li>
</ul>
<p>Both plugins <code>AcolyteMasks.esl</code> and <code>AcolyteMasks.esp</code> will now have their locations displayed in LOOT.</p>
<h4>Regex within LOOT</h4>
<p>Now that we taken the first step to understand what regular expressions are, it should be noted that LOOT currently uses three different regex engines in different places.</p>
<ul>
<li>Masterlist entry matching uses the Rust <code>regress</code> library.</li>
<li>Condition evaluation uses the Rust <code>regex</code> library.</li>
<li>The contains filter and search dialog uses <code>Qt</code>'s regex implementation.</li>
</ul>
<p>These different regex engines support different flavours of regex syntax, but they behave similarly. The most significant differences are:</p>
<ul>
<li>Regexes in conditions do not support lookaround.</li>
<li>The three engines define <code>\d</code>, <code>\D</code>, <code>\w</code>, <code>\W</code>, <code>\s</code> and <code>\S</code> differently for non-<a href="https://en.wikipedia.org/wiki/ASCII#Character_set">ASCII</a> characters.</li>
</ul>
<pre><code> - name: 'Example\.es(m|p)'
msg:
- <<: *useOnlyOneX
subs: [ 'Example Plugin' ]
condition: 'many("Example\.es(m|p)")'
</code></pre>
<p>The regex in the <code>name</code> field uses the Rust <code>regress</code>library.</p>
<p>The regex in the <code>condition</code> field uses the Rust <code>regex</code> library.</p>
<img src="images/Regex_Search_Cards.png" alt="Regex_Search_Cards" width="602" height="409">
<p>The search dialog uses <code>Qt</code>'s regex implementation.</p>
<img src="images/Regex_Filter_Contain.png" alt="Regex_Filter_Contain" width="890" height="570">
<p>The contains filter uses <code>Qt</code>'s regex implementation.</p>
<p>The following section will concentrate on the use of regex in the name field of plugin objects in the masterlist, so that we get a better understanding of what is possible while adding and updating plugin entries.</p>
<h4>Characters and Rules</h4>
<p>The following regular expressions can be used to match characters:</p>
<p><code>\d \D \w \W \s \S</code></p>
<p>Different regex engines define <code>\d</code>, <code>\w</code> and <code>\s</code> differently for non-<a href="https://en.wikipedia.org/wiki/ASCII#Character_set">ASCII</a> characters:</p>
<ul>
<li><code>\d</code> matches any digit character. The <code>regress</code> engine defines <code>\d</code> as matching the digits <code>0</code> to <code>9</code>, but the <code>regex</code> and <code>Qt</code> engines will also match non-ASCII decimal digits such as <code></code>.</li>
<li><code>\w</code> matches any word character. The three engines all define what counts as a word character differently, with too many differences to detail here.</li>
<li><code>\s</code> matches any whitespace character.
<ul>
<li><code>regex</code> matches all Unicode Whitespace characters.</li>
<li><code>Qt</code> matches all Unicode Whitespace characters, plus <code><a href="https://unicode-explorer.com/c/180E">U+180E</a></code>.</li>
<li><code>regress</code> matches all Unicode Whitespace characters except <code><a href="https://unicode-explorer.com/c/0085">U+0085</a></code>, and also matches <code><a href="https://unicode-explorer.com/c/FEFF">U+FEFF</a></code>.</li>
</ul>
</li>
</ul>
<p>The uppercase expressions are easy to define: <code>\D</code> matches everything that doesn't match <code>\d</code>, <code>\W</code> matches everything that doesn't match <code>\w</code>, and <code>\S</code> matches everything that doesn't match <code>\s</code>.</p>
<p>In order to get a feeling what sorts of characters these expressions are capable of matching, let's take the following set of characters as reference:</p>
<p>Digits: <code>0 1 2 3 4 5 6 7 8 9</code></p>
<p>Latin Alphabet: <code>A B C D E F G H I J K L M N O P Q R S T U V W X Y Z</code></p>
<p>Additional Latin Characters: <code>Ä Æ Ö Ü</code></p>
<p>Special Characters: <code>! # $ % & ( ) , . ' ` - ; [ ] ^ _ { } ~ € + = Œ ੩</code></p>
<p>Greek Alphabet: <code>α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ ς τ υ φ χ ψ ω</code></p>
<p>Japanese Hiragana: <code>あ い う え お か き く け こ さ し す せ そ た ち つ て と な に ぬ ね の は ひ ふ へ ほ ま み む め も や ゆ よ ら り る れ ろ わ を ん</code></p>
<p>Japanese Katakana: <code>ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ テ ト ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ マ ミ ム メ モ ヤ ユ ヨ ラ リ ル レ ロ ワ ヲ ン</code></p>
<p>Through testing the following rules could be derived:</p>
<ul>
<li><code>\d</code> can be used exclusively for digits 0 to 9 when using <code>regress</code>, but will also match <code></code> when using <code>regex</code> or <code>Qt</code>.</li>
<li><code>\w</code> can be used for the digits 0 to 9, for any of the normal letters from the Latin Alphabet and for the underscore <code>_</code> when using <code>regress</code>. It will match all of the reference characters above except the symbols <code>! # $ % & ( ) , . ' ` - ; [ ] ^ { } ~ € + =</code> when using <code>Qt</code> or <code>regex</code>.</li>
</ul>
<h3>Regex while Editing</h3>
<h4>Quantifiers</h4>
<h5>Once or none: <code>?</code></h5>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/skyrim/mods/25603/">Map Markers Complete</a></p>
<pre><code> - name: 'Map Markers Complete( DLC| nC| OC)?\.esp'
url:
- link: 'https://www.nexusmods.com/skyrim/mods/25603/'
name: 'Map Markers Complete'
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Map Markers Complete.esp
Map Markers Complete DLC.esp
Map Markers Complete nC.esp
Map Markers Complete OC.esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>After the string <code>Map Markers Complete</code> follows a capturing group <code>( )</code>.</li>
<li>The content of the capturing group has been made optional by adding a question mark <code>?</code> directly after it, so both cases of the capturing groups content being present as well as being absent are valid possible matches.</li>
<li>Inside the capturing group are the alternatives <code> DLC</code>, <code> nC</code> and <code> OC</code> (each string has a leading whitespace), seperated by the OR operand <code>|</code>.</li>
</ul>
<h5>Zero or more times: <code>*</code></h5>
<p>Exemplary masterlist entry:</p>
<pre><code> - name: 'Bashed Patch.*\.esp'
group: *dynamicPatchGroup
after:
- 'SSEMerged.esp'
- 'One ImCh Patch.esp'
- 'One ImCh Patcher.esp'
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Bashed Patch, 0.esp
Bashed Patch, 1.esp
Bashed Patch, 2.esp
...
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>After the string <code>Bashed Patch</code> and before the escaping of the period <code>\.</code> has the term <code>.*</code> been introduced.</li>
<li>The non-escaped period from <code>.*</code> is a regular expression that matches any character except the line break.</li>
<li>The asterisk <code>*</code> after the non-escaped period means <i>zero or more times</i>.</li>
<li>Therefore the above Regex matches any plugin name that begins with <code>Bashed Patch</code>, after which any sort and number of characters may follow, until <code>.esp</code> is found.</li>
</ul>
<p>This means, that in addition to it's standard name <code>Bashed Patch, 0.esp</code> (and also <code>Bashed Patch, 1.esp</code> and <code>Bashed Patch, 2.esp</code>) the following variants would be found by the Regex as well:</p>
<pre><code>Bashed Patch.esp
Bashed Patch_.esp
Bashed PatchAAA.esp
</code></pre>
<p>This goes to show that the above Regex is designed so that it may find differently named Bashed Patch plugins, even though <code>Bashed Patch, 0.esp</code> is and will always be the standard nomenclature for Bashed Patches.</p>
<p>For Wrye Bash the filename of the plugin doesn't matter to begin with, as it is identifying Bashed Patches through the plugins <code>author</code> field containing <code>BASHED PATCH</code> within it.</p>
<p>Also see: <a href="https://wrye-bash.github.io/docs/Wrye%20Bash%20General%20Readme.html#patch">Wrye Bash General Readme</a></p>
<h5>One or more times: <code>+</code></h5>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/skyrimspecialedition/mods/1772/">Rich Skyrim Merchants</a></p>
<pre><code> - name: 'RichMerchantsSkyrim_x\d+\.esp'
url:
- link: 'https://www.nexusmods.com/skyrimspecialedition/mods/1772/'
name: 'Rich Skyrim Merchants'
tag: [ Relev ]
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>RichMerchantsSkyrim_x2.esp
RichMerchantsSkyrim_x5.esp
RichMerchantsSkyrim_x10.esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>The character <code>\d</code> is used to match the digits 0 to 9.</li>
<li>The <code>+</code> means <i>one or more times</i>.</li>
<li>The Regex therefore finds <code>RichMerchantsSkyrim_x</code> followed by one or more digits.</li>
</ul>
<h5>Exactly x times: <code>{x}</code></h5>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/oblivion/mods/23783/">Enhanced Vegetation</a></p>
<pre><code> - name: 'Enhanced Vegetation \[\d{3}%\]\.esp'
url: [ 'https://www.nexusmods.com/oblivion/mods/23783/' ]
msg:
- <<: *useOnlyOneX
subs: [ 'Enhanced Vegetation' ]
condition: 'many("Enhanced Vegetation \[\d{3}%\]\.esp")'
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Enhanced Vegetation [100%].esp
Enhanced Vegetation [110%].esp
Enhanced Vegetation [125%].esp
Enhanced Vegetation [150%].esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>The square brackets <code>[</code> and <code>]</code> have been escaped as well, since otherwise they would be interpreted as a regular expression.</li>
<li>Within the square brackets is the expression <code>\d{3}</code> which meaning becomes <i>exactly three digits</i>.</li>
<li>After this expression then comes a <code>%</code>, which is a normal character and which is needed because the plugin names include it.</li>
<li>Notice that besides for <code>name</code> the regex can also be used for <code>condition</code>.</li>
</ul>
<h5>x or more times: <code>{x,}</code></h5>
<p>Exemplary masterlist entry:</p>
<pre><code> - name: 'Example \d{3,}\.esp'
msg:
- type: say
content:
- lang: en
text: 'A few lines from Skyrim.ini: {0}'
# Other languages omitted for brevity
subs:
- |
```
[Audio]
fMusicDuckingSeconds=6.0
fMusicUnDuckingSeconds=8.0
fMenuModeFadeOutTime=3.0
fMenuModeFadeInTime=1.0
```
</code></pre>
<p>Plugins that are <i>not</i> identified by the above Regex:</p>
<pre><code>Example 1.esp
Example 12.esp
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Example 123.esp
Example 1234.esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>The expression <code>\d{3,}</code> finds plugins that contain three or more digits.</li>
<li>In addition to the regex this example also showcases a method to display blocks of code within a message for plugins.</li>
<li>This is achieved through using the <i>Literal Style</i>, which is denoted by the <code>|</code> indicator. See <a href="https://yaml.org/spec/1.2.2/#23-scalars">yaml.org</a> for more information.</li>
<li>The mentioned <code>Skyrim.ini</code> can be found in <code>C:\Users\USER\Documents\My Games\Skyrim</code></li>
</ul>
<h5>x to y times (inclusive): <code>{x,y}</code></h5>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/skyrim/mods/1178/">Arrowsmith - Reupload</a> | <a href="https://www.nexusmods.com/skyrim/mods/1771/">ArrowsmithES</a></p>
<pre><code> - name: 'Arrowsmith\w{0,2}\.esp'
msg:
- *alreadyInSkyRe
- *alreadyInCompleteCraftingOverhaul
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Arrowsmith.esp
ArrowsmithES.esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>As described in the Rules section is the character <code>\w</code> used to detect the letters from the Latin alphabet, the underscore <code>_</code> as well as digits 0 to 9.</li>
<li>The inclusive expression <code>\w{0,2}</code> therefore finds strings of length zero to two characters.</li>
<li>The plugin name from the orignal upload is <code>Arrowsmith.esp</code>, and the name from from the Spanish translation is <code>ArrowsmithES.esp</code>. The regex <code>\w{0,2}</code> can now detect whether or not <code>ES</code> is absent or present.</li>
</ul>
<h4>Character Classes</h4>
<h5>One of the characters in brackets: <code>[ ... ]</code></h5>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/skyrimspecialedition/mods/30817/">Lanterns Of Skyrim II</a></p>
<pre><code> - name: '(Lanterns Of Skyrim II|LoS II - .*)\.es[mp]'
url:
- link: 'https://www.nexusmods.com/skyrimspecialedition/mods/30817/'
name: 'Lanterns Of Skyrim II'
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Lanterns Of Skyrim II.esm
LoS II - 3DNPC addon.esp
LoS II - BlackthornManor patch.esp
LoS II - Book of Skyrim patch.esp
LoS II - Bruma patch.esp
LoS II - Camp Argentum patch.esp
LoS II - Convenient Bridges patch.esp
LoS II - CEO Windhelm patch.esp
LoS II - ClefJ Winterhold patch.esp
LoS II - CRF patch.esp
LoS II - Camp Varglya patch.esp
LoS II - Campfire addon.esp
LoS II - Dragon Bridge patch.esp
LoS II - Darkwater Crossing patch.esp
LoS II - Eli's Breezehome patch.esp
LoS II - ELFX patch.esp
LoS II - Eli's Riverwood Shack patch.esp
LoS II - Enhanced Solitude SSE patch.esp
LoS II - ETaC patch.esp
LoS II - Fortified Whiterun patch.esp
LoS II - Falkreath patch.esp
LoS II - Helarchen Creek patch.esp
LoS II - HelgenReborn patch.esp
LoS II - Ivarstead patch.esp
LoS II - JKs Skyrim patch.esp
LoS II - JKs Riverwood patch.esp
LoS II - Karthwasten patch.esp
LoS II - Kynesgrove patch.esp
LoS II - Lantern Workers.esp
LoS II - LotD patch.esp
LoS II - Midwood Isle patch.esp
LoS II - Northern Marsh Bridges patch.esp
LoS II - Obscure College of Winterhold patch.esp
LoS II - Old Hroldan Ruins patch.esp
LoS II - Oakwood patch.esp
LoS II - Overstead SE patch.esp
LoS II - RiverwoodHuntingCabin patch.esp
LoS II - Run of the Mill Inn patch.esp
LoS II - Skyrim Bridges patch.esp
LoS II - Solitude Docks patch.esp
LoS II - Solitude Expansion patch.esp
LoS II - Settlements Expanded patch.esp
LoS II - SMIM patch.esp
LoS II - Shor's Stone patch.esp
LoS II - Sounds of Skyrim patch.esp
LoS II - Soljund's Sinkhole patch.esp
LoS II - The Fall of Granite Hill patch.esp
LoS II - TGCoR - SLaWF patch.esp
LoS II - Telengard patch.esp
LoS II - USSEP patch.esp
LoS II - Whistling Mine patch.esp
LoS II - Weathered Road Signs patch.esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>The file extension is written as <code>es[mp]</code>. Each character in the square brackets is a valid match for the regex, so both <code>esm</code> and <code>esp</code> will be identified by it.</li>
<li>A capturing group <code>( )</code> encloses the rest of the plugin name, with the OR operand <code>|</code> seperating the two alternatives <code>Lanterns Of Skyrim II</code> and <code>LoS II - .*</code> within it.</li>
<li>The term <code>.*</code> within the second alternative consists out of the non-escaped period <code>.</code> (a regular expression that matches any character except the line break) and the asterisk <code>*</code> (which means <i>zero or more times</i>).</li>
<li>Therefore the term <code>LoS II - .*</code> matches any plugin name that begins with <code>LoS II - </code> after which any sort and number of characters may follow, until <code>.es[mp]</code> is found.</li>
</ul>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/skyrimspecialedition/mods/6441/">Coins of Tamriel SSE</a></p>
<pre><code> - name: 'Coins of Tamriel( V[234])? SSE( Hardcore)? Edition\.esp'
url: [ 'https://www.nexusmods.com/skyrimspecialedition/mods/6441/' ]
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Coins of Tamriel SSE Edition.esp
Coins of Tamriel V2 SSE Edition.esp
Coins of Tamriel V3 SSE Edition.esp
Coins of Tamriel V4 SSE Edition.esp
Coins of Tamriel SSE Hardcore Edition.esp
Coins of Tamriel V2 SSE Hardcore Edition.esp
Coins of Tamriel V3 SSE Hardcore Edition.esp
Coins of Tamriel V4 SSE Hardcore Edition.esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>Six of the eight plugins include either the term <code>V2</code>, <code>V3</code> or <code>V4</code>.</li>
<li>The expression <code> V[234]</code> will find a leading whitespace, followed by the letter V, followed by either 2,3 or 4.</li>
<li>A capturing group encloses <code>( V[234])?</code> as the next step. The content of the capturing group has been made optional by adding a question mark <code>?</code> directly after it, since two of the eight plugins do not include a version number in their name.</li>
<li>The expression <code>( Hardcore)?</code> also has been made optional (and includes a leading whitespace), since four of the eight plugins include the word Hardcore, and the other four do not.</li>
</ul>
<h5>Range x to y: <code>[x-y]</code></h5>
<p>Exemplary masterlist entry:</p>
<pre><code> - name: 'cc[A-Z]{3}SSE[0-9]{3}.*\.es(l|m)'
group: *ccGroup
</code></pre>
<p>A few examples of plugins that are identified by the above Regex:</p>
<pre><code>ccBGSSSE001-Fish.esm
ccBGSSSE025-AdvDSGS.esm
ccBGSSSE037-Curios.esl
ccQDRSSE001-SurvivalMode.esl
</code></pre>
<p>For more information on Creation Club plugins, see <a href="https://en.uesp.net/wiki/Skyrim:Creation_Club">UESPWiki - Creation Club</a>.</p>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>The file extension is written as <code>es(l|m)</code>, so through the use of a capturing group <code>( )</code> and the OR operand <code>|</code> both <code>esl</code> and <code>esm</code> are valid matches for the regex.</li>
<li>All Creation Club plugin filenames start with <code>cc</code> followed by a set of three varying characters from the Latin alphabet. The regular expression for that is <code>[A-Z]{3}</code>, so exactly three characters from the range A to Z.</li>
<li>After that all Creation Club plugins for Skyrim Special Edition include <code>SSE</code> in their filenames, followed by exactly three digits from the range 0 to 9. The regular expression for that is <code>SSE[0-9]{3}</code>.</li>
<li>After the three digits follows a hyphen <code>-</code> (or in a minority of cases, an underscore <code>_</code>) followed by a descriptive string such as <code>Fish</code> or <code>SurvivalMode</code>.</li>
<li>The regular expression <code>.*</code> matches these strings, so the non-escaped period <code>.</code> which finds all characters except the line break, and the asterisk <code>*</code> that means <i>zero or more</i>.</li>
</ul>
<h5>One character that is not x: <code>[^x]</code></h5>
<p>Exemplary masterlist entry:</p>
<pre><code> - &scriptExtenderMissing
type: error
content: 'You have installed an {0} plugin but {0} was not found! See {0} download page: {1}.'
subs:
- 'SKSE'
- '[SKSE](https://skse.silverlock.org)'
condition: 'file("SKSE/Plugins/([^\.]+\.dll)") and not file("../skse_loader.exe")'
</code></pre>
<p>Here is a small overview of SKSE Plugins which are identified by the above Regex (this list does not claim to be complete):</p>
<table>
<tr>
<th>SKSE Plugin</th>
<th>Mod</th>
</tr>
<tr>
<td>AHZmoreHUDPlugin.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/51956/">moreHUD</a></td>
</tr>
<tr>
<td>BugFixPlugin.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/76747/">Bug fixes</a></td>
</tr>
<tr>
<td>chargen.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/29624/">RaceMenu</a></td>
</tr>
<tr>
<td>ConsolePlugin.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/66257/">ConsoleUtil</a></td>
</tr>
<tr>
<td>CopyPaste.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/100543/">Copy and Paste in Console</a></td>
</tr>
<tr>
<td>CrashFixPlugin.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/72725/">Crash fixes</a></td>
</tr>
<tr>
<td>DisplayEnemyLevel.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/90041/">Display Enemy Level</a></td>
</tr>
<tr>
<td>DoubleJumpPlugin.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/65044/">Better Jumping</a></td>
</tr>
<tr>
<td>DynamicAnimationReplacer.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/101371/">Dynamic Animation Replacer</a></td>
</tr>
<tr>
<td>fiss.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/48265/">FileAccess Interface for Skyrim Script - FISS</a></td>
</tr>
<tr>
<td>FloatingDamage.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/87895/">Floating Damage</a></td>
</tr>
<tr>
<td>havok_fix.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/91598/">(SKSE) Havok Fix</a></td>
</tr>
<tr>
<td>LipSyncFix.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/75951/">Fix Lip Sync</a></td>
</tr>
<tr>
<td>LocationalDamage.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/91505/">Locational Damage</a></td>
</tr>
<tr>
<td>nioverride.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/29624/">RaceMenu</a></td>
</tr>
<tr>
<td>PlayerRotation.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/102937/">Player Rotation in ShowRaceMenu</a></td>
</tr>
<tr>
<td>po3_namedashpiles.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/97046/">Name Those Ash Piles</a></td>
</tr>
<tr>
<td>po3_papyrusextender.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/95017/">powerofthree's Papyrus Extender</a></td>
</tr>
<tr>
<td>po3_SpellPerkItemDistributor.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/105121/">Spell Perk Item Distributor</a></td>
</tr>
<tr>
<td>po3_WashThatBloodOff.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/98546/">Wash That Blood Off</a></td>
</tr>
<tr>
<td>QuickLoot.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/73096/">Quick Loot</a></td>
</tr>
<tr>
<td>SkyrimSouls.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/83379/">SkyrimSouls - Unpaused Game Menus</a></td>
</tr>
<tr>
<td>StorageUtil.dll</td>
<td><a href="https://www.nexusmods.com/skyrim/mods/64798/">Campfire - Complete Camping System</a></td>
</tr>
</table>
<p>Summary:</p>
<ul>
<li>The <code>condition</code> in this example includes the regular expression: <code>file("SKSE/Plugins/([^\.]+\.dll)")</code></li>
<li>The objective is to find <code>.dll</code> files within the folder structure <code>SKSE/Plugins/</code>.</li>
<li>As a first step the period <code>.</code> in front of <code>dll</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>The remaining part of the regex <code>[^\.]+</code> consists out of three parts.</li>
<li><code>[^x]</code> will find a character that is <i>not x</i>, which is achieved by placing the circumflex <code>^</code> within square brackets <code>[ ]</code>. In this case <code>x</code> is an escaped period <code>\.</code> so <i>not a period</i> is what we want. After the square brackets comes the quantifier plus <code>+</code> which means <i>one or more times</i>.</li>
<li>Therefore the regular expression <code>[^\.]+\.dll</code> finds all SKSE plugins, which filesnames include one or more characters that are not a period, and end with <code>.dll</code></li>
</ul>
<h4>Lookarounds</h4>
<h5>Negative lookahead: <code>(?! ...)</code></h5>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/skyrimspecialedition/mods/30247/">Kalilies NPCs</a></p>
<pre><code> - name: '.*(KaliliesNPC|Kalilies NPC)(?! WARP).*\.esp'
url: [ 'https://www.nexusmods.com/skyrimspecialedition/mods/30247/' ]
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>AI Overhaul - KaliliesNPCs Patch.esp
CRF - Kalilies NPC's Patch.esp
KaliliesNPCs.esp
KaliliesNPCs - CRF patch.esp
KaliliesNPCs - USSEP CRF AI Overhaul Patch.esp
Kalilies NPCs + AI Overhaul + Cutting Room Floor Patch.esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>Two capturing groups <code>( )( )</code> enclose different parts of the target filenames.</li>
<li>Before and after the two capturing groups is the regular expression <code>.*</code> (the non-escaped period <code>.</code> matches all characters except the line break, and the asterisk <code>*</code> means <i>zero or more</i>). Placing these before and after the two capturing groups ensures, that around the central strings <code>KaliliesNPC</code> and <code>Kalilies NPC</code> any sort and number of characters is matched and found.</li>
<li>Inside the first capturing group is the OR operand <code>|</code> so that both <code>KaliliesNPC</code> and <code>Kalilies NPC</code> and valid matches.</li>
<li>Inside the second capturing group is the <i>negative lookahead</i> <code>?! WARP</code> to exclude any search results that contain <code>WARP</code> in the filename. This is necessary, since otherwise there is a false positive search result in the form of <code>KaliliesNPCs WARP PATCH.esp</code> from <a href="https://www.nexusmods.com/skyrimspecialedition/mods/33942/">Kalilies NPCs WARP patch</a>. Since it is the purpose of this regex to provide a <code>url</code> for the plugins from the original mod page, and not for the plugin(s) from other mod pages, this is an important and efficient method to achieve the outlined purpose.</li>
<li>It should be noted, that support for lookaround varies by implementation and in LOOT negative lookahead is supported everywhere apart from inside conditions.</li>
</ul>
<h4>More Examples</h4>
<h5>Requiem</h5>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/skyrim/mods/19281/">Requiem - The Roleplaying Overhaul</a></p>
<pre><code> - name: 'Requiem( - (No (Overencumbered )?Messages|Restored (Rewarding Sounds|Saving Messages)|Vanilla Dragonborn DLC))?\.esp'
url:
- link: 'https://www.nexusmods.com/skyrim/mods/19281/'
name: 'Requiem - The Roleplaying Overhaul'
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Requiem.esp
Requiem - No Messages.esp
Requiem - No Overencumbered Messages.esp
Requiem - Restored Rewarding Sounds.esp
Requiem - Restored Saving Messages.esp
Requiem - Vanilla Dragonborn DLC.esp
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>This regular expression is characterized by the fact that it uses multiple capturing groups that are nested into one another.</li>
<li>The outer capturing group <code>( )</code> comes directly after <code>Requiem</code> and it's content it made optional through adding the question mark <code>?</code> directly after it.</li>
<li>Within this outer capturing group we have the following situation: <code> - (a|b|c)</code> with a, b and c being three alternatives seperated by <code>|</code> - the OR operand.</li>
<li><code>a</code> is <code>No (Overencumbered )?Messages</code> and it has it's own capturing group with the optional content <code>Overencumbered </code>.</li>
<li><code>b</code> is <code>Restored (Rewarding Sounds|Saving Messages)</code> and it too has it's own capturing group with the non-optional content <code>Rewarding Sounds|Saving Messages</code>.</li>
<li><code>c</code> is <code>Vanilla Dragonborn DLC</code></li>
</ul>
<h5>Skyrim Project Optimization</h5>
<p>Exemplary masterlist entry: <a href="https://www.nexusmods.com/skyrimspecialedition/mods/14084/">Skyrim Project Optimization SE</a></p>
<pre><code> - name: 'Skyrim Project Optimization - (No Homes - )?Full( ESL)? Version\.esm'
url:
- link: 'https://www.nexusmods.com/skyrimspecialedition/mods/14084/'
name: 'Skyrim Project Optimization SE'
</code></pre>
<p>Plugins that are identified by the above Regex:</p>
<pre><code>Skyrim Project Optimization - Full ESL Version.esm
Skyrim Project Optimization - Full Version.esm
Skyrim Project Optimization - No Homes - Full ESL Version.esm
Skyrim Project Optimization - No Homes - Full Version.esm
</code></pre>
<p>Summary:</p>
<ul>
<li>The period <code>.</code> has been escaped through writing a backslash <code>\</code> in front of it.</li>
<li>All four plugins start with <code>Skyrim Project Optimization - </code> and as such, so does the regex.</li>
<li>Two of the four plugins continue on with <code>No Homes - </code> and the regex accounts for that with the optional capturing group: <code>(No Homes - )?</code></li>
<li>Then all four plugins continue with <code>Full</code> and so does the regex.</li>
<li>Two of the four plugins continue on with <code> ESL</code> and the regex accounts for that with the optional capturing group: <code>( ESL)?</code></li>
<li>All four plugin names and as such the regex end with <code> Version</code> and the file extension.</li>
</ul>
<h3>Regex while Searching</h3>
<h4>General</h4>
<p>The LOOT masterlists are <code>.yaml</code> files that include thousands of lines and data for many different plugins. Sometimes and for specific reasons we found it useful to make use of regular expressions while searching different terms within the masterlists.</p>
<p>For example, in <a href="https://notepad-plus-plus.org/">Notepad++</a> you can switch from the Search Mode <code>Normal</code> to <code>Regular expression</code> to use the following examples.</p>
<img src="images/Notepad_Regular_Expression_01.png" alt="Notepad_Regex_01" width="1300" height="400">
<h4>Examples</h4>
<h5>Find <code>- name: ''</code> entries followed by <code>url</code></h5>
<p>Regular Expression:</p>
<pre><code>- name: '\w{1,}\.\w{3}'\r?\n.*url
</code></pre>
<p>Exemplary search result:</p>
<pre><code> - name: 'SimSettlements.esm'
url: [ 'https://www.nexusmods.com/fallout4/mods/21872' ]
after:
- 'HUDFramework.esm'
- 'WorkshopFramework.esm'
</code></pre>
<p>Summary:</p>
<ul>
<li><code>- name: '\w{1,}\.\w{3}'</code> is the first part of the regex.</li>
<li>Within the two apostrophes <code>''</code> the expression <code>\w{1,}</code> searches for one or more characters of any sort (latin alphabet, digits 0 to 9 and the underscore <code>_</code>), the escaped period <code>\.</code> marks the point the file extension begins and <code>\w{3}</code> is used to find exactly three characters for the file extension (which can either be <code>esm</code>, <code>esp</code> or <code>esl</code>).</li>
<li>The next part of the regex is <code>\r?\n</code>.</li>
<li>The combination <code>\r\n</code> of the carriage return (CR) character <code>\r</code> and the line feed (LF) character <code>\n</code> act together as mechanism to detect a new line of text. It is important to know that while the Windows-style new line consists out of CR LF, files in Git are usually saved with just LF. To ensure that the above regex works in both invironments the question mark <code>?</code> has been added directly after <code>\r</code> to make it optional.</li>
<li>The last part of the regex is <code>.*url</code>.</li>
<li>It consists out of the non-escaped period <code>.</code> which matches all characters except the line break, the asterisk <code>*</code> which means <i>zero or more</i> and the string <code>url</code>.</li>
<li>The full regex is therefore able to find plugin entries, where directly after the <code>- name: ''</code> line the location data with a <code>url</code> follows.</li>
</ul>
<h5>Find <code>- name: ''</code> entries not followed by <code>url</code></h5>
<p>Regular Expression:</p>
<pre><code>- name: '\w{1,}\.\w{3}'\r?\n.*(after|clean|dirty|^display|group|inc|msg|req)
</code></pre>
<p>Exemplary search result:</p>
<pre><code> - name: 'PPF.esm'
clean:
# English
- crc: 0x92CA557D
util: 'FO4Edit v4.0.4b'
</code></pre>
<p>Summary:</p>
<ul>
<li><code>- name: '\w{1,}\.\w{3}'\r?\n.*</code> is exactly the same as in the above regex. The only difference is that instead of <code>url</code> now the capturing group <code>(after|clean|dirty|^display|group|inc|msg|req)</code> is used.</li>
<li>Inside the capturing group <code>( )</code> are the different & alternative keys from the masterlists seperated by the OR operand <code>|</code>, so that every other one <i>except</i> the <code>url</code> is found.</li>
<li>The circumflex <code>^</code> is in front of <code>display</code>, because <code>detail</code> is never found directly under the main <code>name</code> key of a plugin entry.</li>
</ul>
<p>If the <code>display</code> key would not be excluded, false positive search results such as the following one would be found:</p>
<pre><code> - name: 'SS2.esm'
url:
- link: 'https://www.nexusmods.com/fallout4/mods/47976/'
name: 'Sim Settlements 2 (Nexus Mods)'
- link: 'https://bethesda.net/en/mods/fallout4/mod-detail/4183663/'
name: 'Sim Settlements 2 (Bethesda.net Mods)'
inc:
- name: 'Conquest.esp'
display: 'Conquest - Build New Settlements and Camping'
</code></pre>
<h5>Find instances of trailing whitespaces after <code>- name: ''</code></h5>
<p>Regular Expression:</p>
<pre><code>- name: '\w{1,}\.\w{3}'\s$
</code></pre>
<p>Exemplary search result (notice the whitespace at the end):</p>
<pre><code> - name: 'Homemaker.esm'
url: [ 'https://www.nexusmods.com/fallout4/mods/1478/' ]
</code></pre>
<p>What is not found:</p>
<pre><code> - name: 'Homemaker.esm'
url: [ 'https://www.nexusmods.com/fallout4/mods/1478/' ]
</code></pre>
<p>Summary:</p>
<ul>
<li><code>- name: '\w{1,}\.\w{3}'</code> is exactly the same as in the above regex.</li>
<li>The potential whitespace is found by <code>\s</code> and after that the dollar sign <code>$</code> is used to find the end of the line.</li>
</ul>
<h5>Find instances of single line location data</h5>
<p>Regular Expression:</p>
<pre><code>url:\s\[
</code></pre>
<p>Exemplary search result:</p>
<pre><code> - name: 'SettlementKeywords.esm'
url: [ 'https://www.nexusmods.com/fallout4/mods/12226/' ]
</code></pre>
<p>What is not found:</p>
<pre><code> - name: 'ColterFix.esp'
url:
- link: 'https://www.nexusmods.com/fallout4/mods/59323/'
name: 'Overboss Colter Fix'
</code></pre>
<p>Summary:</p>
<ul>
<li>The regex starts with <code>url:</code>, followed by <code>\s</code> to detect whitespace.</li>
<li>After that the opening square bracket is escaped.</li>
</ul>
<h5>Find plugins with x dirty edits</h5>
<p>Regular Expression:</p>
<pre><code>\w{3}: \d{x}
</code></pre>
<p>Exemplary search result for <code>x = 4</code>:</p>
<pre><code> - name: 'Little Cottage on a Hill.esp'
url:
- link: 'https://www.nexusmods.com/skyrim/mods/22773/'
name: 'Little Cottage on a Hill'
dirty:
# v1.0
- <<: *reqManualFix
crc: 0xAB8573E8
util: '[TES5Edit v4.0.4b](https://www.nexusmods.com/skyrim/mods/25859)'
itm: 2733
udr: 44
nav: 1
</code></pre>
<p>Summary:</p>
<ul>
<li>The regex <code>\w{3}: \d{4}</code> follows the way cleaning data is added to the masterlist.</li>
<li>First exactly three characters are searched through <code>\w{3}</code> which in the masterlist in this context can be either <code>itm</code>, <code>udr</code> or <code>nav</code>, after which a colon <code>:</code> follows.</li>
<li>After that an exactly four digit long number is searched (including a leading whitespace) through <code> \d{4}</code>. In this example <code>itm: 2733</code> has been found.</li>
</ul>
<h5>Find Creation Club plugins</h5>
<p>Regular Expressions:</p>
<pre><code>cc\w{3}sse\d{3}
cc\w{3}fo4\d{3}
</code></pre>
<p>Exemplary search results:</p>
<pre><code> - name: 'ccfsvsse001-backpacks.esl'
clean:
- crc: 0x3F8D2754
util: 'SSEEdit v4.0.4'
- name: 'ccbgsfo4076-pipmystery.esl'
clean:
- crc: 0x3FAFF472
util: 'FO4Edit v4.0.2j'
</code></pre>
<p>Summary:</p>
<ul>
<li>All Creation Club plugin filenames start with <code>cc</code> followed by a set of three varying characters from the Latin alphabet. The regular expression to match these three characters is <code>\w{3}</code>.</li>
<li>After that all Creation Club plugins for Skyrim Special Edition include <code>sse</code> in their filenames, followed by exactly three digits from the range 0 to 9. The regular expression for that is <code>sse\d{3}</code>.</li>
<li>For the Fallout 4 Creation Club plugins the next set of characters ist <code>fo4</code> in most cases, and in minority of cases it is <code>f04</code>, followed by exactly three digits from the range 0 to 9. The regular expression for that is <code>fo4\d{3}</code>, though this expression will not find the ones with <code>f04</code>.
<li>After the three digits follows a hyphen <code>-</code> (or in a minority of cases, an underscore <code>_</code>) followed by a descriptive string such as <code>backpacks</code> or <code>pipmystery</code>. Our regex isn't interested in that part however, as it isn't really necessary in order to find the Creation Club plugins - it's good enough already.</li>
<li>As a more general approach, <code>cc\w{6}\d{3}</code> could also be used, and this variation should find all Creation Club plugins from both Skyrim Special Edition and Fallout 4.</li>
<li>You could generalise it even more to <code>cc\w{9}</code> as <code>\w</code> in addition to characters from the latin alphabet & the underscore also finds digits. However, this approach would also easily find false positives such as <code>konahrik_accoutrements.esp</code>.</li>
</ul>
<h5>Find block style single-element lists</h5>
<p>Lists that have only one element that aren't written in flow style can look like the <code>after</code> tag in the following example:</p>
<pre><code> - name: 'InnoLostAlt.esp'
url: [ 'https://www.nexusmods.com/skyrimspecialedition/mods/24236' ]
after:
- 'TheChoiceIsYours.esp'
clean:
- crc: 0x7D8AB5D7
util: 'SSEEdit v4.0.3'
</code></pre>
<p>For consistency reasons we instead write these list like this:</p>
<pre><code> after: [ 'TheChoiceIsYours.esp' ]
</code></pre>
<p>The following regular expression can be used to find such instances:</p>
<pre><code>: *\r?\n {3,}-.*\r?\n {2,4}(?! )
</code></pre>
<p>Additional exemplary search results:</p>
<pre><code> - name: 'after_clean.esp'
after:
- 'TheChoiceIsYours.esp'
clean:
- name: 'msg_clean_1.esp'
msg:
- *includesMBBF
clean:
- name: 'msg_clean_2.esp'
msg:
- <<: *patchRequiem3rdParty
condition: 'not checksum("Rebirth Monster.esp", 3F7371A1)'
subs:
- '[Revenge of the Enemies Patches](https://www.nexusmods.com/skyrim/mods/73369)'
clean:
- name: 'tag_clean.esp'
tag:
- Stats
clean:
</code></pre>
<p>Summary:</p>
<ul>
<li>Finds most occurrences, taking advantage of the expected indentation of such elements & how it will be preceded by a colon & newline & followed by a less indented line.</li>
<li>The regex starts with <code>: *\r?\n</code> to find a colon <code>:</code> after which a whitespace and the asterisk <code>*</code> follow to indicate <i>zero or more</i> whitespaces after the colon. After that <code>\r?\n</code> is used to find an immediately following end of the line. This is done so that for example <code>after:</code> can be matched, after which then the potential single-element list could follow in the next line.</li>
<li>The next step is to find a hyphen <code>-</code> in the next line of text using <code> {3,}-</code>. For this we use a whitespace followed by the quantifier <code>{3,}</code> which as such searches <i>three or more whitespaces</i>, followed by the hyphen <code>-</code>.</li>
<li>After that we continue with <code>.*</code> to find <i>zero or more</i> of characters the non-escaped period (any character except line break) may find after the hyphen (e.g. <code> 'TheChoiceIsYours.esp'</code>) and follow that up with <code>\r?\n</code> to find the end of the second line.</li>
<li>The final step is to use <code> {2,4}(?! )</code> for what comes after the single-element lists. First we use <code> {2,4}</code> to indicate <i>two to four whitespaces</i> followed by a negative lookahead <code>(?! )</code> to rule out any matches with additional whitespaces in this line. A <code>clean</code> tag indented by four spaces would fulfill this check.</li>
</ul>
<p>While this regex is already great in finding single-element lists, it wouldn't find these instances:</p>
<pre><code> - name: 'after_without_clean.esp'
after:
- 'TheChoiceIsYours.esp'
- name: 'msg_without_clean.esp'
msg:
- *includesMBBF
- name: 'tag_without_clean.esp'
tag:
- Stats
</code></pre>
<p>The expression can be improved to find these instances as well:</p>
<pre><code>: *\r?\n {3,}-.*\r?\n( {2,4}(?! )|\r?\n+)
</code></pre>
<ul>
<li><code>{2,4}(?! )</code> has been placed inside a capturing group <code>( )</code> as the first alternative.</li>
<li>Within this capturing group are two alternatives, seperated by the OR operand <code>|</code> and the second alternative is <code>\r?\n+</code> which aim is to find <i>one or more new lines</i> after the second line.</li>
</ul>
<p>While the improved regex already finds all of the above examples, it also finds the following case, which is a false positive search result:</p>
<pre><code> - name: 'Example \d{3,}\.esp'
msg:
- type: say
content:
- lang: en
text: 'A few lines from Skyrim.ini: {0}'
# Other languages omitted for brevity
subs:
- |
```
[Audio]
fMusicDuckingSeconds=6.0
fMusicUnDuckingSeconds=8.0
fMenuModeFadeOutTime=3.0
fMenuModeFadeInTime=1.0
```
</code></pre>
<p>The regex can once again be improved to <i>exclude</i> the above false positive:</p>
<pre><code>: *\r?\n {3,}-[^\r?\n|]*\r?\n( {2,4}(?! )|\r?\n+)
</code></pre>
<ul>
<li>Instead of the non-escaped period in <code>-.*</code> we now use <code>-[^\r?\n|]*</code> to exclude the <code>|</code> character in the next line.</li>
<li>This is achieved through searching <i>one character that is not x</i> with <code>[^x]</code> and <code>x</code> being <code>\r?\n|</code>.</li>
</ul>
<h5>Revisit merger bash tags</h5>
<p>Regular Expressions:</p>
<pre><code>(\[|-|:) *(Actors\.Perks|Invent|Outfits|(R\.)?Relations|Derel)
</code></pre>
<p>Exemplary search results:</p>
<pre><code> - name: 'DeadMoney.esm'
tag:
- Deflst
- Invent.Add
- Invent.Remove
- name: 'KDS Wearable Backpacks.esp'
tag: [ Invent ]
- name: 'NewVegasBountiesII.esp'
tag: [ Relations ]
</code></pre>
<p>Summary:</p>
<ul>
<li>Relevant use case: <a href="https://github.com/loot/loot.github.io/issues/92">Revisit merger tags for WB v310</a></li>
<li>The regex <code>(\[|-|:)</code> is meant to be read as <code>(a|b|c)</code>, so as a capturing group <code>( )</code> where three alternatives are seperated with the OR operand <code>|</code>.</li>
<li>In this example, <code>a</code> would be the escaped opening square bracket <code>[</code>, <code>b</code> would be a hyphen <code>-</code> and <code>c</code> would be the colon <code>:</code></li>
<li>After the capturing group and before the other tags follows a whitespace and an asterisk <code> *</code> to search for <i>zero or more whitespaces</i>.</li>
<li>Another capturing group <code>(Actors\.Perks|Invent|Outfits|(R\.)?Relations|Derel)</code> is used to search for the different tags that should be reevaluated at a later date.</li>
</ul>
<h5>Find NoMerge bash tags</h5>
<p>Regular Expressions:</p>
<pre><code>(\[|-|:) *NoMerge
</code></pre>
<p>Exemplary search results:</p>
<pre><code> - name: 'FNVMerged.esp'
tag: [ NoMerge ]
- name: 'Realistic Weight.esp'
tag:
- NoMerge
- Stats
</code></pre>
<p>What is not found:</p>
<pre><code>bash_tags:
- 'NoMerge'
# NoMerge
</code></pre>
<p>Summary:</p>
<ul>
<li>Relevant use case: <a href="https://github.com/loot/loot.github.io/issues/91">Revisit mods with NoMerge tag for WB v311+</a></li>
<li>The regex <code>(\[|-|:)</code> is meant to be read as <code>(a|b|c)</code>, so as a capturing group <code>( )</code> where three alternatives are seperated with the OR operand <code>|</code>.</li>
<li>In this example, <code>a</code> would be the escaped opening square bracket <code>[</code>, <code>b</code> would be a hyphen <code>-</code> and <code>c</code> would be the colon <code>:</code></li>
<li>After the capturing group and before the NoMerge tag follows a whitespace and an asterisk <code> *</code> to search for <i>zero or more whitespaces</i>.</li>
</ul>
<h3>Find & Replace</h3>
<h4>General</h4>
<p>Find & Replace is a feature of e.g. Notepad++ as well as VSCode, to easily find a specific term and replace it with another, with a single button press.</p>
<p>This presents a great possibility to go through larger tasks that otherwise would need a lot of manual work, however masterlist maintainers should refrain from using automated <code>Replace All</code> functions.</p>
<p>This would certainly decrease the time needed to work on the task at hand, however it would also come with an elevated risk to miss something or replace some parts that weren't intended to be replaced.</p>
<h4>Examples</h4>
<h5>Replace file extension</h5>
<pre><code>Find:
.esp
Replace:
.esl
</code></pre>
<p>Summary:</p>
<ul>
<li>This regex is able to easily replace <code>.esp</code> file extensions to <code>.esl</code>.</li>
</ul>
<h5>Replace Invent Bash Tag</h5>
<pre><code>Find:
\s{6}-\sInvent$
Replace:
- Test
</code></pre>
<p>Summary:</p>
<ul>
<li>Replaces the Bash Tag <code>Invent</code> with <code>Test</code>.</li>
<li>While searching for whitespaces can be done with the regular expression <code>\s</code>, replacing them must be done the normal way.</li>
<li>This means that any number of whitespaces that have been found through a regex (e.g. <code>\s{6}</code>), must be typed individually within the Replace field.</li>
<li>The end of the line is detected with the dollar sign <code>$</code>.</li>
</ul>
<h5>Add missing trailing slashes to Nexus Mods <code>url</code></h5>
<pre><code>Find:
/mods/(\d{1,})'
Replace:
/mods/\1/'
</code></pre>
<p>Exemplary search result:</p>
<pre><code> - name: 'Altitude.esp'
url: [ 'https://www.nexusmods.com/newvegas/mods/71404' ]
</code></pre>
<p>Replacement:</p>
<pre><code> - name: 'Altitude.esp'
url: [ 'https://www.nexusmods.com/newvegas/mods/71404/' ]
</code></pre>
<p>Summary:</p>
<ul>
<li><code>\d{1,}</code> is used to detect <i>one or more</i> digits, to match the mod page number in the link, e.g. <code>71404</code>.</li>
<li>This expression is then placed within a capturing group <code>( )</code>, so that the Replace Field has access to it.</li>
<li>After the capturing group comes an apostrophe <code>'</code> to detect the end of the link that has no trailing slash.</li>
<li><code>\1</code> in the Replace field copies the contents of the first capturing group over from the Find field (in this case there is only one).</li>
<li>As the last step comes <code>/'</code> after <code>\1</code> to add the trailing slash.</li>
</ul>
<h5>Update location data to include a <code>name</code></h5>
<pre><code>Find:
\s{4}url: \[\s(.*)\s\]
Replace:
url:\r\n - link: \1\r\n name: ''
</code></pre>
<img src="images/Notepad_Regular_Expression_02.png" alt="Notepad_Regex_02" width="700" height="357">
<p>Exemplary search result:</p>
<pre><code> - name: 'Altitude.esp'
url: [ 'https://www.nexusmods.com/newvegas/mods/71404/' ]
</code></pre>
<p>Replacement:</p>
<pre><code> - name: 'Altitude.esp'
url:
- link: 'https://www.nexusmods.com/newvegas/mods/71404/'
name: ''
</code></pre>
<p>Summary:</p>
<ul>
<li>Any whitespaces have been added individually within the Replace field.</li>
<li><code>\1</code> in the Replace field copies the contents of the first capturing group over from the Find field (in this case there is only one).</li>
</ul>
<!-- Add empty space at the bottom for scrolling convenience -->
<p style="margin-left: 0;padding: 0 0 40em 0;border-width: 0px; border-color: white; border-style:none;"></p>