private static double ReadDouble(CharIter iter) { int sign = +1; if (iter.NextIf('-')) { sign = -1; } else if (iter.NextIf('+')) { sign = +1; } double intPart; double fracPart = 0; int divisor = 1; intPart = (double)ProcessUnsignedInt(iter); if (intPart < 0) { intPart = 0; } iter.NextIf('.'); char c; while (iter.HasNext() && IsDigit(c = iter.Curr())) { fracPart *= 10; fracPart += c - '0'; divisor *= 10; iter.Next(); } return(sign * (intPart + (fracPart / divisor))); }
/// <summary> /// Positional variation/multi centre bonding. Describe as a begin atom and one or more end points. /// </summary> /// <param name="iter">input characters, iterator is progressed by this method</param> /// <param name="state">output CXSMILES state</param> /// <returns>parse was a success (or not)</returns> private static bool ProcessPositionalVariation(CharIter iter, CxSmilesState state) { if (state.positionVar == null) { state.positionVar = new SortedDictionary <int, IList <int> >(); } while (iter.HasNext()) { if (IsDigit(iter.Curr())) { int beg = ProcessUnsignedInt(iter); if (!iter.NextIf(':')) { return(false); } var endpoints = new List <int>(6); if (!ProcessIntList(iter, DotSeparatorChar, endpoints)) { return(false); } iter.NextIf(','); state.positionVar.Add(beg, endpoints); } else { return(true); } } return(false); }
/// <summary> /// Coordinates are written between parenthesis. The z-coord may be omitted '(0,1,),(2,3,)'. /// </summary> /// <param name="iter">input characters, iterator is progressed by this method</param> /// <param name="state">output CXSMILES state</param> /// <returns>parse was a success (or not)</returns> private static bool ProcessCoords(CharIter iter, CxSmilesState state) { if (state.atomCoords == null) { state.atomCoords = new List <double[]>(); } while (iter.HasNext()) { // end of coordinate list if (iter.Curr() == ')') { iter.Next(); iter.NextIf(','); // optional return(true); } double x = ReadDouble(iter); if (!iter.NextIf(',')) { return(false); } double y = ReadDouble(iter); if (!iter.NextIf(',')) { return(false); } double z = ReadDouble(iter); iter.NextIf(';'); state.coordFlag = state.coordFlag || z != 0; state.atomCoords.Add(new double[] { x, y, z }); } return(false); }
/// <summary> /// CXSMILES radicals. /// </summary> /// <param name="iter">input characters, iterator is progressed by this method</param> /// <param name="state">output CXSMILES state</param> /// <returns>parse was a success (or not)</returns> private static bool ProcessRadicals(CharIter iter, CxSmilesState state) { if (state.atomRads == null) { state.atomRads = new SortedDictionary <int, Radical>(); } CxSmilesState.Radical rad; switch (iter.Next()) { case '1': rad = Monovalent; break; case '2': rad = Divalent; break; case '3': rad = DivalentSinglet; break; case '4': rad = DivalentTriplet; break; case '5': rad = Trivalent; break; case '6': rad = TrivalentDoublet; break; case '7': rad = TrivalentQuartet; break; default: return(false); } if (!iter.NextIf(':')) { return(false); } var dest = new List <int>(4); if (!ProcessIntList(iter, CommaSeparatorChar, dest)) { return(false); } foreach (var atomidx in dest) { state.atomRads.Add(atomidx, rad); } return(true); }
public override Movement Evaluate(Window b, CharIter start) { CharIter end = start; CharIter line = start.LineStart; if (start - line <= 1) { --end; } else { string xs = new Range(line, end).Chars.Trim(); int n = xs == string.Empty ? 2 : 1; end -= n; } return new Movement { CursorRange = new Range(start, end), ActionRange = new Range(start, end) }; }
private static bool SkipIntList(CharIter iter, char sep) { while (iter.HasNext()) { char c = iter.Curr(); if (IsDigit(c) || c == sep) { iter.Next(); } else { return(true); } } // ran off end return(false); }
private static bool SkipIntMap(CharIter iter) { while (iter.HasNext()) { char c = iter.Curr(); if (Char.IsDigit(c) || c == ',' || c == ':') { iter.Next(); } else { return(true); } } // ran of end return(false); }
private static int ProcessUnsignedInt(CharIter iter) { if (!iter.HasNext()) { return(-1); } char c = iter.Curr(); if (!IsDigit(c)) { return(-1); } int res = c - '0'; iter.Next(); while (iter.HasNext() && IsDigit(c = iter.Curr())) { res = res * 10 + c - '0'; iter.Next(); } return(res); }
/// <summary> /// Process a list of unsigned integers. /// </summary> /// <param name="iter">char iter</param> /// <param name="sep">the separator</param> /// <param name="dest">output</param> /// <returns>int-list was successfully processed</returns> private static bool ProcessIntList(CharIter iter, char sep, List <int> dest) { while (iter.HasNext()) { char c = iter.Curr(); if (IsDigit(c)) { int r = ProcessUnsignedInt(iter); if (r < 0) { return(false); } iter.NextIf(sep); dest.Add(r); } else { return(true); } } // ran of end return(false); }
/// <summary> /// Fragment grouping defines disconnected components that should be considered part of a single molecule (i.e. /// Salts). Examples include NaH, AlCl3, Cs2CO3, HATU, etc. /// </summary> /// <param name="iter">input characters, iterator is progressed by this method</param> /// <param name="state">output CXSMILES state</param> /// <returns>parse was a success (or not)</returns> private static bool ProcessFragmentGrouping(CharIter iter, CxSmilesState state) { if (state.fragGroups == null) { state.fragGroups = new List <List <int> >(); } var dest = new List <int>(); while (iter.HasNext()) { dest.Clear(); if (!ProcessIntList(iter, DotSeparatorChar, dest)) { return(false); } iter.NextIf(CommaSeparatorChar); if (dest.Count == 0) { return(true); } state.fragGroups.Add(new List <int>(dest)); } return(false); }
public static void Insert(this Gtk.TextBuffer buffer, CharIter c, string text) { var ti = c.GtkIter; buffer.Insert(ref ti, text); }
/// <summary> /// Parse an string possibly containing CXSMILES into an intermediate state /// (<see cref="CxSmilesState"/>) representation. /// </summary> /// <param name="str">input character string (SMILES title field)</param> /// <param name="state">output CXSMILES state</param> /// <returns>position where CXSMILES ends (below 0 means no CXSMILES)</returns> public static int ProcessCx(string str, CxSmilesState state) { CharIter iter = new CharIter(str); if (!iter.NextIf('|')) { return(-1); } while (iter.HasNext()) { switch (iter.Next()) { case '$': // atom labels and values // dest is atom labels by default SortedDictionary <int, string> dest; // check for atom values if (iter.NextIf("_AV:")) { dest = state.atomValues = new SortedDictionary <int, string>(); } else { dest = state.atomLabels = new SortedDictionary <int, string>(); } if (!ProcessAtomLabels(iter, dest)) { return(-1); } break; case '(': // coordinates if (!ProcessCoords(iter, state)) { return(-1); } break; case 'c': // cis/trans/unspec ignored case 't': // c/t: if (iter.NextIf(':')) { if (!SkipIntList(iter, CommaSeparatorChar)) { return(-1); } } // ctu: else if (iter.NextIf("tu:")) { if (!SkipIntList(iter, CommaSeparatorChar)) { return(-1); } } break; case 'r': // relative stereochemistry ignored if (iter.NextIf(':')) { if (!SkipIntList(iter, CommaSeparatorChar)) { return(-1); } } else { if (!iter.NextIf(',') && iter.Curr() != '|') { return(-1); } } break; case 'l': // lone pairs ignored if (!iter.NextIf("p:")) { return(-1); } if (!SkipIntMap(iter)) { return(-1); } break; case 'f': // fragment grouping if (!iter.NextIf(':')) { return(-1); } if (!ProcessFragmentGrouping(iter, state)) { return(-1); } break; case 'S': // Sgroup polymers if (iter.NextIf("g:")) { if (!ProcessPolymerSgroups(iter, state)) { return(-1); } } else if (iter.NextIf("gD:")) { if (!ProcessDataSgroups(iter, state)) { return(-1); } } else { return(-1); } break; case 'm': // positional variation if (!iter.NextIf(':')) { return(-1); } if (!ProcessPositionalVariation(iter, state)) { return(-1); } break; case '^': // Radicals if (!ProcessRadicals(iter, state)) { return(-1); } break; case 'C': case 'H': // coordination and hydrogen bonding ignored if (!iter.NextIf(':')) { return(-1); } while (iter.HasNext() && IsDigit(iter.Curr())) { if (!SkipIntList(iter, DotSeparatorChar)) { return(-1); } iter.NextIf(','); } break; case '|': // end of CX // consume optional separators if (!iter.NextIf(' ')) { iter.NextIf('\t'); } return(iter.pos); default: return(-1); } } return(-1); }
/// <summary> /// Process atom labels from extended SMILES in a char iter. /// </summary> /// <param name="iter">char iteration</param> /// <param name="dest">destination of labels (atomidx->label)</param> /// <returns>parse success/failure</returns> private static bool ProcessAtomLabels(CharIter iter, SortedDictionary <int, string> dest) { int atomIdx = 0; while (iter.HasNext()) { // fast forward through empty labels while (iter.NextIf(';')) { atomIdx++; } char c = iter.Next(); if (c == '$') { iter.NextIf(','); // optional // end of atom label return(true); } else { iter.pos--; // push back var beg = iter.pos; var rollback = beg; while (iter.HasNext()) { if (iter.pos == beg && iter.Curr() == '_' && iter.Peek() == 'R') { ++beg; } // correct step over of escaped label if (iter.Curr() == '&') { rollback = iter.pos; if (iter.NextIf('&') && iter.NextIf('#') && iter.NextIfDigit()) { while (iter.NextIfDigit()) { } // more digits if (!iter.NextIf(';')) { iter.pos = rollback; } else { } } else { iter.pos = rollback; } } else if (iter.Curr() == ';') { break; } else if (iter.Curr() == '$') { break; } else { iter.Next(); } } dest.Add(atomIdx, Unescape(iter.Substr(beg, iter.pos))); atomIdx++; if (iter.NextIf('$')) { iter.NextIf(','); // optional return(true); } if (!iter.NextIf(';')) { return(false); } } } return(false); }
public void PlaceCursorKeepVisible(CharIter i) { Model.Value.PlaceCursor(i.GtkIter); CursorMovedByCommand.Handler(i); }
public override Movement Evaluate(Window b, CharIter start) { var range = new Range(start, start + 1); return new Movement { CursorRange = range, ActionRange = range }; }
/// <summary> /// Polymer Sgroups describe variations of repeating units. Only the atoms and not crossing bonds are written. /// </summary> /// <param name="iter">input characters, iterator is progressed by this method</param> /// <param name="state">output CXSMILES state</param> /// <returns>parse was a success (or not)</returns> private static bool ProcessPolymerSgroups(CharIter iter, CxSmilesState state) { if (state.sgroups == null) { state.sgroups = new List <PolymerSgroup>(); } var beg = iter.pos; while (iter.HasNext() && !IsSgroupDelim(iter.Curr())) { iter.Next(); } var keyword = iter.Substr(beg, iter.pos); if (!iter.NextIf(':')) { return(false); } var atomset = new List <int>(); if (!ProcessIntList(iter, CommaSeparatorChar, atomset)) { return(false); } string subscript; string supscript; if (!iter.NextIf(':')) { return(false); } // "If the subscript equals the keyword of the Sgroup this field can be empty", ergo // if omitted it equals the keyword beg = iter.pos; while (iter.HasNext() && !IsSgroupDelim(iter.Curr())) { iter.Next(); } subscript = Unescape(iter.Substr(beg, iter.pos)); if (string.IsNullOrEmpty(subscript)) { subscript = keyword; } // "In the superscript only connectivity and flip information is allowed.", default // appears to be "eu" either/unspecified if (!iter.NextIf(':')) { return(false); } beg = iter.pos; while (iter.HasNext() && !IsSgroupDelim(iter.Curr())) { iter.Next(); } supscript = Unescape(iter.Substr(beg, iter.pos)); if (string.IsNullOrEmpty(supscript)) { supscript = "eu"; } if (iter.NextIf(',') || iter.Curr() == '|') { state.sgroups.Add(new CxSmilesState.PolymerSgroup(keyword, atomset, subscript, supscript)); return(true); } // not supported: crossing bond info (difficult to work out from doc) and bracket orientation return(false); }
public abstract Movement Evaluate(Window b, CharIter start);
public override Movement Evaluate(Window b, CharIter cursorStart) { var actionStart = cursorStart.LineStart.ForwardLines(1); var actionEnd = actionStart.BackwardLines(2); var cursorEnd = cursorStart.BackwardLines(1); return new Movement { CursorRange = new Range(cursorStart, cursorEnd), ActionRange = new Range(actionStart, actionEnd) }; }
private static bool ProcessDataSgroups(CharIter iter, CxSmilesState state) { if (state.dataSgroups == null) { state.dataSgroups = new List <DataSgroup>(4); } var atomset = new List <int>(); if (!ProcessIntList(iter, CommaSeparatorChar, atomset)) { return(false); } if (!iter.NextIf(':')) { return(false); } var beg = iter.pos; while (iter.HasNext() && !IsSgroupDelim(iter.Curr())) { iter.Next(); } string field = Unescape(iter.Substr(beg, iter.pos)); if (!iter.NextIf(':')) { return(false); } beg = iter.pos; while (iter.HasNext() && !IsSgroupDelim(iter.Curr())) { iter.Next(); } string value = Unescape(iter.Substr(beg, iter.pos)); if (!iter.NextIf(':')) { state.dataSgroups.Add(new CxSmilesState.DataSgroup(atomset, field, value, "", "", "")); return(true); } beg = iter.pos; while (iter.HasNext() && !IsSgroupDelim(iter.Curr())) { iter.Next(); } var operator_ = Unescape(iter.Substr(beg, iter.pos)); if (!iter.NextIf(':')) { state.dataSgroups.Add(new CxSmilesState.DataSgroup(atomset, field, value, operator_, "", "")); return(true); } beg = iter.pos; while (iter.HasNext() && !IsSgroupDelim(iter.Curr())) { iter.Next(); } var unit = Unescape(iter.Substr(beg, iter.pos)); if (!iter.NextIf(':')) { state.dataSgroups.Add(new CxSmilesState.DataSgroup(atomset, field, value, operator_, unit, "")); return(true); } beg = iter.pos; while (iter.HasNext() && !IsSgroupDelim(iter.Curr())) { iter.Next(); } string tag = Unescape(iter.Substr(beg, iter.pos)); state.dataSgroups.Add(new CxSmilesState.DataSgroup(atomset, field, value, operator_, unit, tag)); return(true); }
public override Movement Evaluate(Window b, CharIter start) { if (count == 0) { return new Movement() { CursorRange = new Range(start, start), ActionRange = new Range(start, start) }; } Movement firstMovement = cmd.Evaluate(b, start); Movement lastMovement = firstMovement; for (uint i = 1; i < count; ++i) { lastMovement = cmd.Evaluate(b, lastMovement.CursorRange.End); } return new Movement() { CursorRange = new Range(firstMovement.CursorRange.Start, lastMovement.CursorRange.End), ActionRange = new Range(firstMovement.ActionRange.Start, lastMovement.ActionRange.End) }; }