7
$\begingroup$

I am new to this site so I hope my question is valid.

My code is:

molekule = InputString[];
Select[ChemicalData[#, "StandardName"] & /@ ChemicalData[],
StringMatchQ[#, ___ ~~ molekule ~~ ___, IgnoreCase -> True] &]

When the input is "Sulfuric" it correctly finds "SulfuricAcid". But when the input is "Sulfuric Acid" it returns an empty list. Why? And the search is really slow, how can I make this faster?

$\endgroup$
5
  • $\begingroup$ It seems that chemical name in Wolfram Language has no spaces... That is why "SulfuricAcid" works and does not with a space. $\endgroup$ Commented Jan 9, 2018 at 13:12
  • $\begingroup$ StringTrim does not eliminate whitespaces between words $\endgroup$ Commented Jan 9, 2018 at 13:17
  • $\begingroup$ @JoséAntonioDíazNavas I am sorry, I meant StringDelete[molekule," "]. But when I input "Acid Sulfuric" it still returns an empty list. $\endgroup$
    – JonD123
    Commented Jan 9, 2018 at 13:20
  • $\begingroup$ Why is the identifier "molekule" instead of "molecule"? $\endgroup$
    – Nat
    Commented Jan 9, 2018 at 19:05
  • 3
    $\begingroup$ @Nat For the same reason I might use "molekula" instead of "molecule". :) $\endgroup$ Commented Jan 10, 2018 at 0:11

3 Answers 3

11
$\begingroup$

Consider using a dedicated search pattern making function. Here is an example.

molekule = "Sulfuric Acid";

Clear[MakeSearchPattern]
MakeSearchPattern[s_String] := 
  StringExpression @@ 
   Join[{BlankNullSequence[]}, 
    Riffle[StringSplit[ToLowerCase[s]], 
     BlankNullSequence[]], {BlankNullSequence[]}];

MakeSearchPattern[molekule]

(* ___ ~~ "sulfuric" ~~ ___ ~~ "acid" ~~ ___ *)

Select[ChemicalData[#, "StandardName"] & /@ ChemicalData[], 
 StringMatchQ[#, MakeSearchPattern[molekule], IgnoreCase -> True] &]

(* {"SulfuricAcid", "SulfuricAcidSolution", \
"DeuteratedSulfuricAcidDeuteriumOxide", "PeroxysulfuricAcid", \
"NitrosylsulfuricAcid", "SodiumSaltSulfuricAcid,MonohexylEster", \
"TitaniumIVOxysulfateSulfuricAcidHydrate", \
"CeriumIVSulfateHydrate,ComplexWithSulfuricAcid"} *)

Update : more complicated search

is there any way to fix the exmpty list that is returned when exchanging Acid with Sulfuric ("Acid Sulfuric" instead of "Sulfuric Acid")

The following function

  1. does the search with the straight string and the reverse string first,

  2. if the result is empty, searches for each search word are made and the most frequent results are returned first.

The second, fall-back step can be slow since multiple searches are made. Note that the result of the first step is extended to be pairs of {_String,_Integer} in order to make the return values of MoleculeSearch consistent.

Clear[MoleculeSearch]
MoleculeSearch[s_String] :=
  Block[{swords, pats, res},
   swords = StringSplit[ToLowerCase[s]];
   pats = Map[MakeSearchPattern, swords];
   res = Select[ChemicalData[#, "StandardName"] & /@ ChemicalData[], 
     StringMatchQ[#, 
       MakeSearchPattern[swords] | MakeSearchPattern[Reverse[swords]],
        IgnoreCase -> True] &];
   If[Length[res] > 0, Transpose[{res, ConstantArray[1, Length[res]]}],
    res = 
     Flatten@Map[
       Function[{sp}, 
        Select[ChemicalData[#, "StandardName"] & /@ ChemicalData[], 
         StringMatchQ[#, sp, IgnoreCase -> True] &]], pats];
    SortBy[Tally[res], -#[[2]] &]
    ]
   ];

MoleculeSearch["acid sulfuric"]

(* {{"SulfuricAcid", 1}, {"SulfuricAcidSolution", 
  1}, {"DeuteratedSulfuricAcidDeuteriumOxide", 
  1}, {"PeroxysulfuricAcid", 1}, {"NitrosylsulfuricAcid", 
  1}, {"SodiumSaltSulfuricAcid,MonohexylEster", 
  1}, {"TitaniumIVOxysulfateSulfuricAcidHydrate", 
  1}, {"CeriumIVSulfateHydrate,ComplexWithSulfuricAcid", 1}} *)

Take[MoleculeSearch["acid sulfuric ester"], UpTo[20]]

(* {{"SodiumSaltSulfuricAcid,MonohexylEster", 3}, {"1,1,4,4Tetramethyl1,4ButanediylEsterHexaneperoxoicAcid,\
2Ethyl", 2}, \
{"1,1Benzyl3Hydroxy2OxoPropylcarbamoyl2PhenylEthylCarbamicAcidBenzylEs\
ter", 2}, \
{"1,1DimethylethylEster1H,5H,11H1Benzopyrano6,7,\
8IjQuinolizine10CarboxylicAcid,2,3,6,7Tetrahydro11Oxo", 
  2}, {"1,1DimethylethylEster2ButeneperoxoicAcid", 
  2}, {"1,1DimethylethylEsterHexaneperoxoicAcid,2Ethyl", 
  2}, {"1,1FerrocenediboronicAcidBisPinacolEster", 
  2}, {"1,1Methyl4,\
5DioxoPent2Enylcarbamoyl2PhenylEthylCarbamicAcidBenzylEster", 
  2}, {"124CarbamimidoylPhenylaminoMethyl1Methyl1hBenzoimidazol5YlCycl\
opropylPyridin2YlMethyleneaminooxyAceticAcidEthylEster", 
  2}, {"1,2Chlorophenyl3,\
5Dimethyl1hPyrazole4CarboxylicAcidEthylEster", 
  2}, {"12HydroxyoctadecanoicAcidMethylEster", 
  2}, {"1,3Hydroxy2Oxo1PhenethylPropylcarbamoyl2PhenylEthylCarbamicAci\
dPyridin4YlmethylEster", 
  2}, {"1,4Aminophenyl3,5Dimethyl1hPyrazole4CarboxylicAcidEthylEster",
   2}, {"1,4BenzenediboronicAcidBisPinacolEster", 
  2}, {"1,4Methoxyphenyl3,\
5Dimethyl1hPyrazole4CarboxylicAcidEthylEster", 
  2}, {"1,4PhenylenebisMethyleneEsterSelenocyanicAcid", 
  2}, {"16DoxylStearicAcidMethylEster", 
  2}, {"1Benzylpyrazole4BoronicAcidPinacolEster", 
  2}, {"1BocIndole5BoronicAcidPinacolEster", 
  2}, {"1Cyclohexen1YlBoronicAcidPinacolEster", 2}} *)
$\endgroup$
5
  • $\begingroup$ This is exactly what I was looking for. Thank you! $\endgroup$
    – JonD123
    Commented Jan 9, 2018 at 13:29
  • $\begingroup$ Ok, good. I was thinking that you also might want to extend the code so the search results to include partial matches... $\endgroup$ Commented Jan 9, 2018 at 13:36
  • $\begingroup$ is there any way to fix the exmpty list that is returned when exchanging Acid with Sulfuric ("Acid Sulfuric" instead of "Sulfuric Acid") $\endgroup$
    – JonD123
    Commented Jan 9, 2018 at 13:36
  • $\begingroup$ You are looking for a search engine solution. A simple way to do that is to merge results of partial matches of the search string. I will probably update my answer with that in the next few hours. $\endgroup$ Commented Jan 9, 2018 at 13:54
  • 1
    $\begingroup$ If you want the names you can get them even faster from the FE by just calling CADumpTriePacket on the ChemicalData autocomplete trie. $\endgroup$
    – b3m2a1
    Commented Jan 10, 2018 at 4:50
5
$\begingroup$

You could use Interpreter:

molekule=InputString[];
Interpreter["Chemical"][molekule]

This approach won't work for strings like "Sulfuric" (too many matches) or "Acid sulfuric" (wrong order), but it will work with different cases, misspellings and formulas:

Interpreter["Chemical"]["sulfuric acid"]
Interpreter["Chemical"]["sufuric acid"]
Interpreter["Chemical"]["H2SO4"]

Entity["Chemical", "SulfuricAcid"]

Entity["Chemical", "SulfuricAcid"]

Entity["Chemical", "SulfuricAcid"]

$\endgroup$
1
$\begingroup$

This seems to work. Just load once ChemicalData[] and then retrieve the information:

ChemicalData[];
molekule = StringDelete[" "][InputString[]];
ChemicalData[molekule]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.