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$
  • $\begingroup$ It seems that chemical name in Wolfram Language has no spaces... That is why "SulfuricAcid" works and does not with a space. $\endgroup$ – José Antonio Díaz Navas Jan 9 '18 at 13:12
  • $\begingroup$ StringTrim does not eliminate whitespaces between words $\endgroup$ – José Antonio Díaz Navas Jan 9 '18 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 Jan 9 '18 at 13:20
  • $\begingroup$ Why is the identifier "molekule" instead of "molecule"? $\endgroup$ – Nat Jan 9 '18 at 19:05
  • 2
    $\begingroup$ @Nat For the same reason I might use "molekula" instead of "molecule". :) $\endgroup$ – Anton Antonov Jan 10 '18 at 0:11
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$
  • $\begingroup$ This is exactly what I was looking for. Thank you! $\endgroup$ – JonD123 Jan 9 '18 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$ – Anton Antonov Jan 9 '18 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 Jan 9 '18 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$ – Anton Antonov Jan 9 '18 at 13:54
  • $\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 Jan 10 '18 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, privacy policy and cookie policy

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