2012-12-11 33 views
0

我想要解析字符串(使用給定的格式)的通用解決方案。例如,我想能夠解析包含數值列表(整數或浮點數)的字符串並返回std :: vector。這是我到目前爲止有:使用模板來實現通用字符串解析器

template<typename T, typename U> 
T parse_value(const U& u) { 
    throw std::runtime_error("no parser available"); 
} 

template<typename T> 
std::vector<T> parse_value(const std::string& s) { 
    std::vector<std::string> parts; 
    boost::split(parts, s, boost::is_any_of(",")); 
    std::vector<T> res; 
    std::transform(parts.begin(), parts.end(), std::back_inserter(res), 
      [](const std::string& s) { return boost::lexical_cast<T>(s); }); 
    return res; 
} 

此外,我希望能夠解析包含其他類型的值的字符串。例如:

struct Foo { /* ... */ }; 

template<> 
Foo parse_value(const std::string& s) { 
    /* parse string and return a Foo object */ 
} 

保持parse_value功能單一的「層次」的原因是因爲,有時候,我想分析一個可選值(可能存在或不),使用boost ::可選。理想情況下,我想有隻是一個單一的parse_optional_value功能,將委託上相應的parse_value功能:

template<typename T> 
boost::optional<T> parse_optional_value(const boost::optional<std::string>& s) { 
    if (!s) return boost::optional<T>(); 
    return boost::optional<T>(parse_value<T>(*s)); 
} 

到目前爲止,我目前的解決方案不起作用(編譯器不能推斷出確切功能使用)。我想問題是我的解決方案依賴於基於返回類型parse_value函數推導模板值。我不確定如何解決這個問題(甚至是否可以修復它,因爲設計方法可能完全有缺陷)。有沒有人知道一種方法來解決我想要做的事情?如果您能指出我解決我目前實施中遇到的問題的可能方法,我將非常感激。順便說一句,我對於解決這個問題的觀點也完全不同。

+0

調用類型爲「parse_value」的I.e'parse_value (str)' – Nim

+0

@Nim當我直接調用'parse_value'解析一個整數向量時,但是我不能從'parse_optional_value'做到這一點。至少我看不到如何...... – betabandido

+0

是否有一個原因是你避免了現有的解析器庫,例如[Boost.Spirit](http://www.boost.org/libs/spirit/)? – ildjarn

回答

1

您不能基於返回值[1]重載函數。這也正是爲什麼標準IO庫使用結構:

std::cin >> a >> b; 

這可能不是你的一塊蛋糕 - 很多人不喜歡它,它是真正並非沒有問題 - 但它確實爲解析器提供一個目標類型。它也比靜態的parse<X>(const std::string&)原型具有優勢,它允許鏈接和流式傳輸,如上所述。有時候這不是必需的,但在許多解析上下文中,這是非常重要的,而且使用operator>>實際上是一個非常酷的語法。 [2]

標準庫不會做什麼將是最酷的事情,即跳過字符串常量scanf樣式並允許交錯讀取。

vector<int> integers; 
std::cin >> "[" >> interleave(integers, ",") >> "]"; 

然而,這可以被定義。 (可能最好在字符串文字中使用明確的包裝,但實際上我更喜歡這種方式;但是如果你傳遞一個變量,你會想使用包裝)。


[1]隨着新auto聲明,這樣做的原因變得更加清晰。

[2] IO操縱器,另一方面,是一個殘酷的笑話。而錯誤處理是可悲的。但你不能擁有一切。

0

這裏是libsass解析器的一個示例:

const char* interpolant(const char* src) { 
    return recursive_scopes< exactly<hash_lbrace>, exactly<rbrace> >(src); 
} 

// Match a single character literal. 
// Regex equivalent: /(?:x)/ 
template <char chr> 
const char* exactly(const char* src) { 
    return *src == chr ? src + 1 : 0; 
} 

其中規則可以被傳遞入方法法。