2016-08-12 9 views
3

私は、いくつかのURIで構成される文字列の醜い混乱を抱えています。私がやりたい何std :: regexを使用して入力をフィルタリングする

:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/0_301_0.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02011.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02012.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02110000.svg 

は文字:/.,のすべての発生を取り除くので、私は有効なファイル名になり、単一の文字列を持つことができます。

私はこの簡単な正規表現を書いています。[^(:/,.)] http://www.regexpal.com/によると正しい正規表現です。

しかし、次のC++コードを実行すると、期待していたもの(英数字とアンダースコアのみ)が返されません。シーケンスの最初の英数字が返されます。S

私はstd :: regexで間違って何をしていますか、正規表現をオフにしていますか?

#include <iostream> 
#include <regex> 
#include <string> 

static const std::string filenames {R"(:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/0_301_0.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02011.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02012.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02110000.svg)"}; 
static const std::regex filename_extractor("[^(:/,.)]"); 

int main() { 
    std::smatch filename_match; 
    if(std::regex_search(filenames, filename_match, filename_extractor)) 
    { 
     std::cout << "Number of filenames: " << filename_match.size() << std::endl; 
     for(std::size_t i = 0; i < filename_match.size(); ++i) 
     { 
      std::cout << i << ": " << filename_match[i] << std::endl; 
     } 
    } 

    return 0; 
} 
+4

私はあなたが 'std :: regex_replace'を望んでいると思っていますが、これはおそらくregexを全く使わない方が良いでしょう。たぶん[std :: remove_if](http://en.cppreference.com/w/cpp/algorithm/remove)を見てください。 – Galik

+0

私は分かりません。あなたの文字列には、 ':/'はなく、 ':/'が含まれていますか?代わりにそれを分割することはできませんか? – rustyx

答えて

3

size()std::smatchの場合、部分式の数+1(()、あなたは持っていない)。

ソリューションは、あなたは繰り返しstd::regex_searchを呼び出す、またはstd::regex_iteratorを使用する必要があります。

さらに、正規表現は実際には1文字のみを検索しました。 [^(:/,.)]+の中で最も長い文字列を検索するには、+を使用する必要があります。ここで

cppreference.comから例を取り入れた、あなたのコードです:

#include <iostream> 
#include <iterator> 
#include <regex> 
#include <string> 

static const std::string filenames {R"(:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/0_301_0.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02011.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02012.svg,:/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02110000.svg)"}; 
static const std::regex filename_extractor("[^(:/,.)]+"); 

int main() { 
    auto files_begin = std::sregex_iterator(filenames.begin(), filenames.end(), filename_extractor); 

    for (auto i = files_begin; i != std::sregex_iterator(); ++i) { 
     std::string filename = i->str(); 
     std::cout << filename << '\n'; 
    } 

    return 0; 
} 

しかし、これはまた、中間の "ディレクトリ" を返します。 あなたが正規表現[^(:,)]+を使用する場合は、結果を得る私はあなたが持っていると思った期待:

/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/0_301_0.svg 
/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02011.svg 
/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02012.svg 
/SymbolStandards/JMSymbology/MIL_STD_2525D_Symbols/02110000.svg 

あなたの問題は、唯一の正規表現の最初出現のために

std::regex_search検索を説明およびその中のすべての部分式。

たとえば、式ab([cd])([ef])は、文字列xxabcfxxabdefと一致します。 最初の一致はabcfの部分で、cは最初の部分式[cd]と一致し、eは2番目の部分式[ef]と一致します。

2番目の一致は、abdeabdefではなく)の部分です。ここで、eは2番目の部分式の一致です。

std::regex_searchとすると、最初の一致を検索すると、が最初にと一致し、サブ式の一致が返されます。 さらに一致するものを探したい場合は、残りの文字列(std::smatch::suffix())から検索を開始する必要があります。

さらに、正規表現[ef]は1文字にのみ一致します。 [ef]+は、e秒とf秒の最長シーケンスと一致します。 したがって、上記のターゲット文字列の第2サブ式ab([cd])([ef])の一致は、eだけでなく、efと一致します。

2

私はstd::regex_replaceはあなたがここに必要なものだと思う:

#include <regex> 
#include <string> 
#include <iostream> 

const std::string filenames {R"(:/MIL_STD/0_3.svg,:/SS/2525D/02011.svg)"}; 
const std::regex filename_extractor("[(:/,.)]"); 

int main() 
{ 
    std::string r; 

    std::regex_replace(std::back_inserter(r), 
     filenames.begin(), filenames.end(), filename_extractor, ""); 

    std::cout << "before: " << filenames << '\n'; 
    std::cout << " after: " << r << '\n'; 
} 

私は正規表現は、あなたがstd::remove_copy_ifでより効率的にこれを行うことができます文字を除去するため、おそらくやり過ぎだと思うしかし:

#include <string> 
#include <iostream> 
#include <algorithm> 

const std::string filenames {R"(:/MIL_STD/0_3.svg,:/SS/2525D/02011.svg)"}; 
const std::string filename_extractor("(:/,.)"); 

int main() 
{ 
    std::string r; 

    std::remove_copy_if(filenames.begin(), filenames.end(), 
     std::back_inserter(r), [](char c) 
    { 
     return filename_extractor.find(c) != std::string::npos; 
    }); 

    std::cout << "before: " << filenames << '\n'; 
    std::cout << " after: " << r << '\n'; 
} 
関連する問題