Sort field content alphabetically with external workaround for missing $sort function

From time to time users ask for a solution to sort the contents of fields, like here or here or here.

Currently, we don't have any $sort function for this task up to Mp3tag version v3.28h.

So I wrote an external workaround for this.

You need
a) a CMD-Batchfile, I call it SortTheContentIn.cmd
and
b) a PowerShell-Script: SortStringBySeparator.ps1
and
c) a installed and working Windows-PowerShell, at least in version v2.0
and
d) a new Mp3tag Tools entry, I call it "Split content by separator, Sort the content and Write it into a new file"
and
e) a new Mp3tag Action to import the sorted field content

The CMD-Batchfile SortTheContentIn.cmd contains the call of the PowerShell-Script, including the ExecutionPolicy Bypass to start it:

@ECHO OFF
SET InputString=%1
SET Delimiter=%2
SET OutputFile=%3
SET ps="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
SET psscript=SortStringBySeparator.ps1

REM PowerShell-Skript aufrufen, Bypass ExecutionPolicy 
%ps% -ExecutionPolicy Bypass -File %psscript% -InputString %InputString% -Delimiter %Delimiter% -OutputFile %OutputFile%

The PowerShell-Script: SortStringBySeparator.ps1 contains

param (
    [string]$InputString,   # Der zu sortierende, komplette String
    [string]$Delimiter,     # Das Trennzeichen
    [string]$OutputFile     # Der Name der Ausgabedatei
)

# String in ein Array aufteilen, dabei abschliessendes Trennzeichen entfernen, leere Elemente filtern, sortieren, Duplikate entfernen und wieder zusammenfügen
$output = ($InputString.TrimEnd($Delimiter) -split [regex]::Escape($Delimiter) | Where-Object { $_ -ne "" } | Sort-Object | Select-Object -Unique) -join $Delimiter

# Ergebnis in die Ausgabeddatei schreiben
Set-Content -Path $OutputFile -Value $output

# Bestätigungsausgabe
Write-Output "Der sortierte String wurde in die Datei '$OutputFile' geschrieben."

# 5 Sekunden auf Tastendruck warten oder nach Ablauf automatisch beenden
TIMEOUT /T 5

This script reads the given String, the delimiter and the name of the outputfile.
The split and sorted output is written in the outpufile name.

The new Mp3tag Tools entry "Split content by separator, Sort the content and Write it into a new file" needs two values:
a) The complete path to the above CMD-Batchfile SortTheContentIn.cmd
and
b) 3 Parameters:
The fieldname (like MOVEMENTNAME containing the unsorted String)
The delimiter/separator character (like a semicolon followed by a space)
The ouptut filename for the sorted string (like %title%_SortedContent.txt)
I recommend to enclose every of these 3 parameters in double quotes " "
Don't forget to select "for all selected files"

Then we need the final step to import the sorted content back in the tag field.
I name the Action "Import sorted field content".
The type of Action is "Import text file".
You can choose any target Field you like. To be 200% sure that it will work correctly, I recommend choosing a custom field like MVT_TMP1. This allows you to double-check that everything is working correctly without overwriting your original MOVEMENTNAME content.
As the Filename you must use the same output filename (such as %title%_SortedContent.txt) that you selected in the Tools definition:

You can now select your files in the File List of Mp3tag, right-click and choose Tools and select Split content by separator, Sort the content and Write it into a new file. This write an output file for every track in the same directory.
With the Action "Import sorted field content" you can re-import the sorted output.

All these steps will lead to these results:
image
image
image

If you are absolutely sure that everything is working as expected, you can copy the contents of the temporary MVT_TMP1 into your original field name. Use an Action or Convert Tag->Tag for this task.
You can then delete the temporary MVT_TMP1.


This would all be much simpler if we had a $sort(x,y,z) script command.
x would be the import string/the original field name,
y would be the delimiter
and
z would be the destination field.
Omitting z would write the sorted contents into the original field.

This is not true anymore!
Since Mp3tag v3.28i we now can use the new available $sort function.

What I forgot:

As Mp3tag can not delete files with an Action, you need to cleanup the no more needed %title%_SortedContent.txt manually.
It should be easy to sort your files by file type or search for _SortedContent.txt and then delete the no more needed files.

I've added a sort functions with Mp3tag v3.28i, where you can sort a given string that is delimited by a given delimiter, e.g., $sort('c;a;b',';')

2 Likes

That was fast! Thanks.

The new $sort needs some little fine-tuning:
Vocal Trance; Trance; Dream; House;
becomes:

As you can see in the above PowerShell-script, the last (mostly not needed) delimiter needs to be removed first, otherwise it will result in a double delimiter somewhere.

Using only a semicolon (without space) shows:

I don't want to be a feature creep ...
Looking at this suggestion

the function is missing (very hard word) the switch for ascending or descending sort order.

Not sure if I want to go in that direction, because strictly speaking, the delimiter is "; " (= semicolon-space) and not ";" (semicolon).

Treating the trailing semicolon as delimiter works in the example, but might not be intended in other contexts.

An possible solution in such cases is to use

$sort($trim('Vocal Trance; Trance; Dream; House;',';'),'; ');

Thanks, I've added a note to my internal wish list.

If someone provides a practical real-life example demonstrating the need for this, I'll consider adding a third parameter for the sort order.

Personally, I can live with this workaround.
Not sure about other users though.

I would use it this way to indicate which trailing semicolon has to be removed
from
Vocal Trance; Trance; Dream; House;
to

And combined with the new $sort command, I get the expected result as you stated.

I'm just not sure if other users may see the not so obvious difference in a leading space switching between position 0 and the words Trance; and Vocal Trance in this example:
$sort and $trim

Perhaps I should have praised the new function first.
I just took a file with lyrics

"Xxx||To the Moon, Through the Stars 
There We'll Find a Place to Be
Close Your Eyes, 
All These Wonders in the Dark 
We Saw Them Shine
You and Me" 

and used $sort($replace(%unsyncedlyrics%,Xxx||,),$char(13)$char(10))
and got

"All These Wonders in the Dark 
Close Your Eyes, 
There We'll Find a Place to Be
To the Moon, Through the Stars 
We Saw Them Shine
You and Me"

So it works also on more or less any list, it seems.

For anyone who needs it "Sort the contents of the field alphabetically separated by \\"

example field: PERFORMER

text in random order

Strings: The London Session Orchestra\\Score: William Jones\\Engineer [Assistant]: Howard Bargroff, Max Bloom\\Vibraphone [Vibes]: Frank Ricotti\\Written-By: C. Womack, G. Noble, L. Womack\\Leader [Orchestral Leader]: Gavyn Wright\\Piano: Pete Wingfield\\Programmed By [Programming]: Mel Wesson\\Guitar: Taj Wyzgowski\\Drums: Rupert Brown\\Arranged By [Arrangement]: Nick Ingam\\Engineer: Martin Hayles\\Flute, Electronic Wind Instrument: Phil Todd\\Percussion: Miles Bould\\Backing Vocals [Background Vocals]: Linda Gerald, Lorraine McIntosh, Tee Green\\Producer: Michael Peden

Convert tag-tag

FIELD: PERFORMER

Format string:
$sort($meta_sep(performer,\\\\),'\\')

preview

Arranged By [Arrangement]: Nick Ingam\\Backing Vocals [Background Vocals]: Linda Gerald, Lorraine McIntosh, Tee Green\\Drums: Rupert Brown\\Engineer [Assistant]: Howard Bargroff, Max Bloom\\Engineer: Martin Hayles\\Flute, Electronic Wind Instrument: Phil Todd\\Guitar: Taj Wyzgowski\\Leader [Orchestral Leader]: Gavyn Wright\\Percussion: Miles Bould\\Piano: Pete Wingfield\\Producer: Michael Peden\\Programmed By [Programming]: Mel Wesson\\Score: William Jones\\Strings: The London Session Orchestra\\Vibraphone [Vibes]: Frank Ricotti\\Written-By: C. Womack, G. Noble, L. Womack

works perfectly thanks Florian!

Great! Just a tip, you can simplify to

$sort($meta_sep(performer,\\),\\)

1 Like