Regular Expression

I like to have all my classical by opus number.
This is a matter of parsing the composition.
If have done so with MP3Tag and with JRiver.
In both cases it is a matter of a lot of If/Then/Else to parse all possible combinations.

One day a forum member MrC advised to use Regular Expression, Regex for short.

 

 

If(IsEmpty(ListItem(FixCase([Album],4),1,d.)),
 If(IsEmpty(ListItem(FixCase([Album],4),1,bwv)),
  If(IsEmpty(ListItem(FixCase([Album],4),1,op.)),
   If(IsEmpty(ListItem(FixCase([Album],4),1,woo)),
    If(IsEmpty(ListItem(FixCase([Album],4),1,kv)),
     ,
     KV ListItem(FixCase([Album],4),1,kv)
     ),
     WoO ListItem(FixCase([Album],4),1,woo)
     ),
    Op. ListItem(ListItem(Replace(Replace(FixCase([Album],4),/(,;),-,;),1,op.),0)
    ),
  BWV ListItem(FixCase([Album],4),1,bwv)
  ),
D. ListItem(ListItem(Replace(Replace(FixCase([Album],4),/(,;),/,,;),1,d.),0)

)

 

This is what I have used.

 

Regex([Composition], /#(Op\.|BWV) ?([^(]+)#/, -1)/
   if(isequal([R1], op., 1), FixCase([R1],2),[R1]) [R2]

 

This is what MrC advised.

The good news: it works
The bad news: I don’t understand why.

Regex

The syntax is:

Regex(String to test, Regular expression, Mode, Case sensitivity)

A safe one is:

Regex(String to test, /#Regular expression#/, Mode, Case sensitivity)

The opening /# and closing #/ is to avoid JRiver expression engine to interpret the Regex.
Everything between /# and #/ is delivered straight to the Regex engine.

 

I have compositions like:

Quartet for String #6 Op. 18/6 "La Malinconia" in B flat Major

Suite for Cello #1 BWV 1007 in G Major

 

The concept behind Regex is to match strings.

 

Regex([Composition], /#Op\.|BWV#/,0)

Output mode=0 is a logical test

The output is a 1 (true) or a 0 (not true)

| (Alternation) acts as an "or"

This test for Op. (you need to escape the . to use it as a literal) or BWV is in Composition.

 

Regex([Composition], /#Op\.|BWV#/,1)

Output mode=1 is the first match of the expression.

The result is no output at all!

 

Regex([Composition], /#(Op\.|BWV)#/,1)

() is a capture group. The moment you use one you get output.

 

The trick is to formulate a pattern to match what comes after Op.

 

Regex([Composition], /#(Op\.|BWV) (\d)#/,-1) [R1] [R2]

To get more output we need a second capture group.

Set the output mode to -1, use two JRiver system variables R1 and R2 to capture the output of the capture groups.

(\d) means match numbers

 

Obvious \d matches a single number, I need them all.

There is also the / in 18/1

Regex([Composition], /#(Op\.|BWV) (\d.*\d)#/,-1) [R1] [R2]

Note the <space> between ) (

This say match Op.<space>Any Number

(\d.*\d) say match any numbers and there might be any character (the dot) in between and it might be as long as needed (the *=repetition)

 

Solved!

Then you start browsing your collection.

(\d.*\d) doesn't work with a single number.

It says it should start with a number and end with a number and any character in between is fine but this excludes a single number.

Regex([Composition], /#(Op\.|BWV) ?(\d.*\d|\d)#/,-1) [R1] [R2]

(\d.*\d|\d) say also match if there is a single number.

 

It doesn't work if there is no <space> between the Op. and the number.

Of course one can manually correct this but what about

Regex([Composition], /#(Op\.|BWV) ?([\d.*\d])#/,-1) [R1] [R2]

) ?( says there should be a space between the two but it is not mandatory (?)

Sometimes opus numbers ends in a character.

Regex([Composition], /#(Op\.|BWV) ?(\d.*\d[a-z]?|\d)#/,-1) [R1] [R2]

(\d.*\d[a-z]?) specify a range [a-z] but it is not mandatory (?)

Examples

if the filename is like

C:\Music\Classical\Gustav Leonhardt\Bach - Brandenburg Concertos - Leonhardt\CD2\01 1. Allegro.flac

Regex([filename], /#(cd)([\d.*\d])#/,-1) [R2]

will extract the CD number

 

 

References
  1. Regular-Expressions.info
  2. TR1 Regular Expressions - Microsoft
  3. Regular Expression Syntax - Microsoft
  4. Media Center expression language - JRiver
  5. Trying to understand Regex - JRiver forum