From 8e6d53d18bc68a569dbe871647ac66cc43f9bafd Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Sat, 19 Nov 2016 17:14:24 -0500 Subject: [PATCH] Enable parsing of composition strings when species names contain colons --- .../cython/cantera/test/test_convert.py | 5 ++-- src/base/stringUtils.cpp | 30 +++++++++++++++++-- test/data/species-names.inp | 5 ++-- test/general/string_processing.cpp | 9 ++++++ 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/interfaces/cython/cantera/test/test_convert.py b/interfaces/cython/cantera/test/test_convert.py index dda512c90..45113caef 100644 --- a/interfaces/cython/cantera/test/test_convert.py +++ b/interfaces/cython/cantera/test/test_convert.py @@ -145,13 +145,13 @@ class chemkinConverterTest(utilities.CanteraTest): self.assertEqual(gas.n_species, 7) self.assertEqual(gas.species_name(0), '(Parens)') self.assertEqual(gas.species_name(1), '@#$%^-2') - self.assertEqual(gas.species_index('co:lons'), 2) + self.assertEqual(gas.species_index('co:lons:'), 2) self.assertEqual(gas.species_name(3), '[xy2]*{.}') self.assertEqual(gas.species_name(4), 'plus+') self.assertEqual(gas.species_name(5), 'eq=uals') self.assertEqual(gas.species_name(6), 'plus') - self.assertEqual(gas.n_reactions, 6) + self.assertEqual(gas.n_reactions, 7) nu = gas.product_stoich_coeffs() - gas.reactant_stoich_coeffs() self.assertEqual(list(nu[:,0]), [-1, -1, 0, 2, 0, 0, 0]) self.assertEqual(list(nu[:,1]), [-2, 3, 0, -1, 0, 0, 0]) @@ -159,6 +159,7 @@ class chemkinConverterTest(utilities.CanteraTest): self.assertEqual(list(nu[:,3]), [3, 0, 0, 0, -2, -1, 0]) self.assertEqual(list(nu[:,4]), [2, 0, 0, 0, -1, 0, -1]) self.assertEqual(list(nu[:,5]), [1, 0, 0, 0, 1, -1, -1]) + self.assertEqual(list(nu[:,6]), [2, 0, -1, 0, 0, -1, 0]) def test_unterminatedSections(self): with self.assertRaises(ck2cti.InputParseError): diff --git a/src/base/stringUtils.cpp b/src/base/stringUtils.cpp index 37b822930..44f8b19bb 100644 --- a/src/base/stringUtils.cpp +++ b/src/base/stringUtils.cpp @@ -121,8 +121,9 @@ compositionMap parseCompString(const std::string& ss, size_t start = 0; size_t stop = 0; + size_t left = 0; while (stop < ss.size()) { - size_t colon = ss.find(':', start); + size_t colon = ss.find(':', left); if (colon == npos) { break; } @@ -137,8 +138,33 @@ compositionMap parseCompString(const std::string& ss, throw CanteraError("parseCompString", "Duplicate key: '" + name + "'."); } - x[name] = fpValueCheck(ss.substr(valstart, stop-colon-1)); + + double value; + try { + value = fpValueCheck(ss.substr(valstart, stop-colon-1)); + } catch (CanteraError& err) { + // If we have a key containing a colon, we expect this to fail. In + // this case, take the current substring as part of the key and look + // to the right of the next colon for the corresponding value. + // Otherwise, this is an invalid composition string. + std::string testname = ss.substr(valstart, stop-colon-1); + if (testname.find_first_of(" \n\t") != npos) { + // Space, tab, and newline are never allowed in names + throw; + } else if (ss.substr(valstart, stop-colon-1).find(':') != npos) { + left = colon + 1; + continue; + } else { + throw; + } + } + x[name] = value; start = ss.find_first_not_of(", ;\n\t", stop+1); + left = start; + } + if (left != start) { + throw CanteraError("parseCompString", "Unable to parse key-value pair:" + "\n'{}'", ss.substr(start, stop)); } if (stop != npos && !ba::trim_copy(ss.substr(stop)).empty()) { throw CanteraError("parseCompString", "Found non-key:value data " diff --git a/test/data/species-names.inp b/test/data/species-names.inp index 7c6c9384c..10a30ad64 100644 --- a/test/data/species-names.inp +++ b/test/data/species-names.inp @@ -2,7 +2,7 @@ Elements H C End SPEC -(Parens) @#$%^-2 co:lons [xy2]*{.} plus+ eq=uals plus +(Parens) @#$%^-2 co:lons: [xy2]*{.} plus+ eq=uals plus end thermo @@ -15,7 +15,7 @@ thermo 7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2 -9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3 -4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4 -co:lons C 1H 4 G 200.000 3500.000 1000.000 1 +co:lons: C 1H 4 G 200.000 3500.000 1000.000 1 7.48514950E-02 1.33909467E-02-5.73285809E-06 1.22292535E-09-1.01815230E-13 2 -9.46834459E+03 1.84373180E+01 5.14987613E+00-1.36709788E-02 4.91800599E-05 3 -4.84743026E-08 1.66693956E-11-1.02466476E+04-4.64130376E+00 4 @@ -44,5 +44,6 @@ plus+ + (Parens) = 2plus+ 9.999e9 9.9 999.9 2 plus+ + eq=uals = 3(Parens) 9.999e9 9.9 999.9 plus + plus+ = 2 (Parens) 9.999e9 9.9 999.9 plus+ eq=uals = plus++(Parens) 9.999e9 9.9 999.9 +co:lons: + eq=uals = 2 (Parens) 9.999e9 9.9 999.9 end diff --git a/test/general/string_processing.cpp b/test/general/string_processing.cpp index 578a0b937..0c347df3d 100644 --- a/test/general/string_processing.cpp +++ b/test/general/string_processing.cpp @@ -24,6 +24,15 @@ TEST(parseCompString, extra_spaces) ASSERT_DOUBLE_EQ(1e-4, c["baz"]); } +TEST(parseCompString, name_with_colon) +{ + compositionMap c = parseCompString("foo: 1.0 co:lon:2,baz: 1e-4"); + ASSERT_EQ((size_t) 3, c.size()); + ASSERT_DOUBLE_EQ(1.0, c["foo"]); + ASSERT_DOUBLE_EQ(2.0, c["co:lon"]); + ASSERT_DOUBLE_EQ(1e-4, c["baz"]); +} + TEST(parseCompString, default_values) { std::vector x = { "foo", "bar", "baz" };