From 672b988c5e68d8e8fb35b5347849984decb1d202 Mon Sep 17 00:00:00 2001
From: Martyn Gigg <martyn.gigg@stfc.ac.uk>
Date: Wed, 25 Jul 2012 12:06:17 +0100
Subject: [PATCH] Add Strings function to create a map from key/val pairs. Refs
 #5644

---
 .../Kernel/inc/MantidKernel/Strings.h         |  5 ++
 Code/Mantid/Framework/Kernel/src/Strings.cpp  | 38 +++++++++++--
 .../Framework/Kernel/test/StringsTest.h       | 57 +++++++++++++++++++
 3 files changed, 95 insertions(+), 5 deletions(-)

diff --git a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Strings.h b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Strings.h
index 46a574b16f5..5f20df7c10f 100644
--- a/Code/Mantid/Framework/Kernel/inc/MantidKernel/Strings.h
+++ b/Code/Mantid/Framework/Kernel/inc/MantidKernel/Strings.h
@@ -9,6 +9,7 @@
 #include <set>
 #include <sstream>
 #include <vector>
+#include <map>
 #include <iterator>
 
 namespace Mantid
@@ -135,6 +136,10 @@ namespace Mantid
       /// Split tring into spc deliminated components
       MANTID_KERNEL_DLL std::vector<std::string> StrParts(std::string Ln);
 
+      /// Splits a string into key value pairs
+      MANTID_KERNEL_DLL std::map<std::string,std::string>
+      splitToKeyValues(const std::string & input, const std::string & keyValSep = "=", const std::string & listSep=",");
+
       /// Write a set of containers to a file
       template<template<typename T,typename A> class V,typename T,typename A>
       int writeFile(const std::string& Fname,const T & step,const V<T,A>& Y);
diff --git a/Code/Mantid/Framework/Kernel/src/Strings.cpp b/Code/Mantid/Framework/Kernel/src/Strings.cpp
index 56b507f8b57..5ad7310b021 100644
--- a/Code/Mantid/Framework/Kernel/src/Strings.cpp
+++ b/Code/Mantid/Framework/Kernel/src/Strings.cpp
@@ -1,14 +1,17 @@
-#include "MantidKernel/Exception.h"
 #include "MantidKernel/Strings.h"
+#include "MantidKernel/Exception.h"
+
+#include <Poco/StringTokenizer.h>
+#include <Poco/Path.h>
+
 #include <cmath>
 #include <fstream>
 #include <iomanip>
 #include <iosfwd>
 #include <iostream>
 #include <list>
-#include <Poco/Path.h>
 #include <sstream>
-#include <string.h>
+#include <cstring>
 #include <vector>
 
 using std::size_t;
@@ -432,13 +435,38 @@ namespace Mantid
        *  @return vector of components
        */
       std::vector<std::string> StrParts(std::string Ln)
-    {
+      {
         std::vector<std::string> Out;
         std::string Part;
         while(section(Ln,Part))
           Out.push_back(Part);
         return Out;
-    }
+      }
+
+      /**
+       * Splits a string into key value pairs and returns them as a map. Whitespace between separators is ignored
+       * @param input :: The string containing the key/values
+       * @param keyValSep :: The separator that splits a key and value [default: "="]
+       * @param listSep :: The separator that splits elements of the list [default: ","]
+       * @returns A map of keys->values
+       */
+      std::map<std::string,std::string>
+      splitToKeyValues(const std::string & input, const std::string & keyValSep, const std::string & listSep)
+      {
+        std::map<std::string,std::string> keyValues;
+        const int splitOptions = Poco::StringTokenizer::TOK_IGNORE_EMPTY + Poco::StringTokenizer::TOK_TRIM;
+        Poco::StringTokenizer listSplitter(input, listSep);
+        for(auto iter = listSplitter.begin(); iter != listSplitter.end(); ++iter)
+        {
+          Poco::StringTokenizer keyValSplitter(*iter, keyValSep, splitOptions);
+          if(keyValSplitter.count() == 2)
+          {
+            keyValues[keyValSplitter[0]] = keyValSplitter[1];
+          }
+        }
+
+        return keyValues;
+      }
 
 
       //------------------------------------------------------------------------------------------------
diff --git a/Code/Mantid/Framework/Kernel/test/StringsTest.h b/Code/Mantid/Framework/Kernel/test/StringsTest.h
index f04ef08b367..0f229294750 100644
--- a/Code/Mantid/Framework/Kernel/test/StringsTest.h
+++ b/Code/Mantid/Framework/Kernel/test/StringsTest.h
@@ -182,6 +182,63 @@ public:
     TS_ASSERT_EQUALS(X,9.0);
   }
 
+  void test_SplitToKeyValuePairs_Returns_Empty_Map_For_Empty_String()
+  {
+    auto keyValues = splitToKeyValues("");
+
+    TS_ASSERT(keyValues.empty());
+  }
+
+  void test_SplitToKeyValuePairs_Returns_Empty_Map_For_String_With_No_Values()
+  {
+    auto keyValues = splitToKeyValues("key,key,key");
+
+    TS_ASSERT(keyValues.empty());
+  }
+
+  void test_SplitToKeyValuePairs_Uses_Equals_And_Comma_As_Separators_By_Default()
+  {
+    auto keyValues = splitToKeyValues("key1=value1, key2=value2");
+
+    TS_ASSERT_EQUALS(keyValues.size(), 2);
+    TS_ASSERT_EQUALS(keyValues.at("key1"), "value1");
+    TS_ASSERT_EQUALS(keyValues.at("key2"), "value2");
+  }
+
+  void test_SplitToKeyValuePairs_Uses_KeyValueSep_If_Given()
+  {
+    auto keyValues = splitToKeyValues("key1@value1, key2@value2", "@");
+
+    TS_ASSERT_EQUALS(keyValues.size(), 2);
+    TS_ASSERT_EQUALS(keyValues.at("key1"), "value1");
+    TS_ASSERT_EQUALS(keyValues.at("key2"), "value2");
+  }
+
+  void test_SplitToKeyValuePairs_Uses_KeyValueSep_And_ListSep_If_Given()
+  {
+    auto keyValues = splitToKeyValues("key1@value1: key2@value2", "@", ":");
+
+    TS_ASSERT_EQUALS(keyValues.size(), 2);
+    TS_ASSERT_EQUALS(keyValues.at("key1"), "value1");
+    TS_ASSERT_EQUALS(keyValues.at("key2"), "value2");
+  }
+
+  void test_SplitToKeyValuePairs_Does_Not_Ignore_Spaces_Within_Key_Or_Value()
+  {
+    auto keyValues = splitToKeyValues("key 1@value1: key2@value 2", "@", ":");
+
+    TS_ASSERT_EQUALS(keyValues.size(), 2);
+    TS_ASSERT_EQUALS(keyValues.at("key 1"), "value1");
+    TS_ASSERT_EQUALS(keyValues.at("key2"), "value 2");
+  }
+
+  void test_SplitToKeyValuePairs_Ignores_Items_Without_A_Key_Or_Value()
+  {
+    auto keyValues = splitToKeyValues("key1=,key2=value2,=value3");
+
+    TS_ASSERT_EQUALS(keyValues.size(), 1);
+    TS_ASSERT_EQUALS(keyValues.at("key2"), "value2");
+  }
 
   void test_join()
   {
-- 
GitLab