# Extract values from strings according to units

I have a lot of strings, which have simple nomenclature of number-unit associations and am looking to extract the number according to the units. For example:

d = {"sam1_80.mV_500nm", "sam1_trial2_450nm_300.mV", "sam2_1.1V_6mum"};


Which displays information for 2 samples, which have either mV or V voltages, and lengths with units of nm or mum, which I wish to sort according to the units and combine into a table with rows {Sample,Voltage,Length}. I can get something which does this:

{StringCases[#, "sam" ~~ (x : NumberString) :> ToExpression[x]],
StringCases[#, (x : NumberString) ~~ "mV" :>
ToExpression[x]] /. {} ->
0 + StringCases[#, (x : NumberString) ~~ "V" :>
ToExpression[x]*1000] /. {} -> 0,
StringCases[#, (x : NumberString) ~~ "nm" :>
ToExpression[x]] /. {} ->
0 + StringCases[#, (x : NumberString) ~~ "mum" :>
ToExpression[x]*1000] /. {} -> 0}[[All, 1]] & /@ d

out:{{1,80.,500},{1,300.,450},{2,1100.,6000}}


However, this seems very messy to me, and I'm wondering if there's a more elegant/simple form.

{"sample", "voltage", "length"} /. StringCases[
d,
Flatten @ {
"sam" ~~ sn : NumberString :> ("sample" -> ToExpression[sn]),
m : (NumberString ~~ LetterCharacter ... ~~ #2) :> (# -> QuantityMagnitude[m, #3]) & @@@ {
{"voltage", "V", "mV"}, {"length", "m", "nm"}}(*name - base unit - final unit*)
}
]


{{1, 80.0, 500}, {1, 300.0, 450}, {2, 1.10*10^3, 6000}}

You could use Interpreter to extract the quantities with the units preserved.

Interpreter["Quantity"] /@ Take[#, -2] & @ StringSplit[#, "_"] & /@ d

InputForm @ %
(*
{{Quantity[80., "Millivolts"], Quantity[500, "Nanometers"]},
{Quantity[450, "Nanometers"], Quantity[300., "Millivolts"]},
{Quantity[1.1, "Volts"], Quantity[6, "Micrometers"]}}
*)