From 6eef5a88d689a997aa2610ebdbf9f8333f2e5498 Mon Sep 17 00:00:00 2001 From: Wolfgang Bangerth Date: Tue, 24 Feb 2015 17:45:39 -0600 Subject: [PATCH] Clarify some of the corner cases of the split_string_list() function. --- include/deal.II/base/utilities.h | 40 +++++++++++++++++++++++++++++--- source/base/utilities.cc | 21 +++++++++++++---- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/include/deal.II/base/utilities.h b/include/deal.II/base/utilities.h index 52f0f25b62..7a45c412da 100644 --- a/include/deal.II/base/utilities.h +++ b/include/deal.II/base/utilities.h @@ -113,10 +113,44 @@ namespace Utilities /** * Given a string that contains text separated by a @p delimiter, split it * into its components; for each component, remove leading and trailing - * spaces. - * - * The default value of the delimiter is a comma, so that the function + * spaces. The default value of the delimiter is a comma, so that the function * splits comma separated lists of strings. + * + * To make data input from tables simpler, if the input string ends in + * a delimiter (possibly followed by an arbitrary amount of whitespace), + * then this last delimiter is ignored. For example, + * @code + * Utilities::split_string_list("abc; def; ghi; ", ';'); + * @endcode + * yields the same 3-element list of output {"abc","def","ghi"} + * as you would get if the input had been + * @code + * Utilities::split_string_list("abc; def; ghi", ';'); + * @endcode + * or + * @code + * Utilities::split_string_list("abc; def; ghi;", ';'); + * @endcode + * As a consequence of this rule, a call like + * @code + * Utilities::split_string_list(" ; ", ';'); + * @endcode + * yields a one-element list. Because of the trimming of + * whitespace, the single element is the empty string. + * + * This function can digest the case that the delimiter is a space. In this + * case, it returns all words in the string. Combined with the rules above, + * this implies that + * @code + * Utilities::split_string_list("abc def ghi ", ' '); + * @endcode + * yields again the 3-element list of output {"abc","def","ghi"} + * from above despite the presence of space at the end of the string. + * Furthermore, + * @code + * Utilities::split_string_list(" ", ' '); + * @endcode + * yields an empty list regardless of the number of spaces in the string. */ std::vector split_string_list (const std::string &s, diff --git a/source/base/utilities.cc b/source/base/utilities.cc index d6cb0fb560..50551b4b8e 100644 --- a/source/base/utilities.cc +++ b/source/base/utilities.cc @@ -197,11 +197,23 @@ namespace Utilities split_string_list (const std::string &s, const char delimiter) { + // keep the currently remaining part of the input string in 'tmp' and + // keep chopping elements of the list off the front std::string tmp = s; + + // as discussed in the documentation, eat whitespace from the end + // of the string + while (tmp.length() != 0 && tmp[tmp.length()-1] == ' ') + tmp.erase (tmp.length()-1, 1); + + // split the input list until it is empty. since in every iteration + // 'tmp' is what's left of the string after the next delimiter, + // and since we've stripped trailing space already, 'tmp' will + // be empty at one point if 's' ended in a delimiter, even if + // there was space after the last delimiter. this matches what's + // discussed in the documentation std::vector split_list; split_list.reserve (std::count (tmp.begin(), tmp.end(), delimiter)+1); - - // split the input list while (tmp.length() != 0) { std::string name; @@ -215,10 +227,9 @@ namespace Utilities else tmp = ""; - while ((name.length() != 0) && - (name[0] == ' ')) + // strip spaces from this element's front and end + while ((name.length() != 0) && (name[0] == ' ')) name.erase (0,1); - while (name.length() != 0 && name[name.length()-1] == ' ') name.erase (name.length()-1, 1); -- 2.39.5