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.
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 (?)

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