Regular expressions - eevdriet/obsidian-anki GitHub Wiki

A regular expression (regex) can be used to define how notes are exported from Obsidian. Each regex should consist of at least one capture group that capture the value of a field of the note. Alternatively, you can also use templates.

Introduction

Regular expressions allows for a very flexible way to search through text for something that you're looking for. If you're not yet familiar with regular expressions, I recommend

  • RegExInfo for initial learning and as documentation source
  • regex101 for testing whether your regexes work as intended

To give one example that I like to use to define a Basic note with a Front and Back field:

^([\w\s]+) -> ([\w\s]+) #note/basic$

This regex can be broken down as follows:

Element Meaning
^ ... $ The note is placed on a single line of text
([\w\s]+) One or more words separated by white space, which resembles the Front
-> Arrow to separate the Front and Back
([\w\s]+) One or more words separated by white space, which resembles the Back
#note/basic Tag to indicate a basic note

Capture groups

If you've used a template before, you can think of a capture group like a field pattern. In our example above, there a 2 capture groups which are delimited by () with whatever you're trying to capture in between. The idea is to set the note's fields from whatever is captured by these groups. When the regex is applied, the 1st group sets the 1st field, the 2nd group sets the 2nd field and so on. One caveat is that at least one group needs to be non-empty for a note to be recognized in text.

Consider again the regex for Basic notes

^([\w\s]*) -> ([\w\s]*) #note/basic$

Below you can see how the regex works and what text its groups capture:

el gato -> the cat #note/basic    <!-- OK: `Front` is captured by "el gato" and `Back` is captured by "the cat" -->

el gato -> #note/basic            <!-- OK: `Front` is captured by "el gato" and `Back` is not captured -->

-> the cat #note/basic            <!-- OK: `Front` is not captured and `Back` is captured by "the cat" -->

#note/basic                       <!-- ERROR: `Front` and `Back` are not captured as both groups are empty -->

Field order

One downside to setting the fields in order of the capture groups is that you have to define a capture group for every field in the regex. Consider a note type Country that has the following fields:

  1. Name
  2. Capital
  3. Language
  4. Currency

Now suppose you want your notes to set the Name and Currency, but you don't care about the Capital and Language. Setting the fields in order, you'd have to define empty capture groups () just to have the 4th group set the Currency. This is cumbersome, especially if you have note types with many fields.

Instead you can define a custom field order such that any group can set any field: Example custom field order

Now you can use the regex

^(\w\s)+ pays with (\w\s)+ #note/country$

for your Country notes, where

  • Name and Currency are set from the 1st and 2nd capture groups respectively
  • Capital and Language are not set at all

Examples

To get an understanding of how regular expressions work in practice, below are some examples. These highlight what errors might come up when defining your own and when notes are or are not matched to a given regex.

Common errors

The template can never be empty

The template should include {{Front}}, {{Back}} or {{Fields}} to make it valid

The template includes invalid pattern {{Middle}}, which should be removed

Matching notes

For these examples, we will use the Basic note type.

  • First consider the following template:
    Deck: {{Deck}}
    {{Tags}}
    {{Front}} -> {{Back}}
    
    Below are some notes defined in the text and whether they match the template.
    Deck: Language::Spanish                 <!-- MATCH: note exported with -->
                                            <!-- - {{Deck}} set as "Language::Spanish" and {{Tags}} not set -->
    el gato -> the cat                      <!-- - {{Front}} set as "el gato" and {{Back}} set as "the cat" -->
    
    Deck:                                   <!-- MATCH: note exported with -->
    language/spanish, language/word         <!-- - {{Deck}} not set and {{Tags}} set as ["language/spanish", "language/word"] -->
    el gato ->                              <!-- - {{Front}} set as "el gato" and {{Back}} not set -->
    
    Deck:                                   <!-- MATCH: note exported with -->
                                            <!-- - {{Deck}} and {{Tags}} not set -->
    -> the cat                              <!-- - {{Front}} not set and {{Back}} set as "the cat" -->
    
    Deck: Language::Spanish                 <!-- NO MATCH: literal text "->" in the template is not matched -->
    language/spanish, language/word
    el gato - the cat