вложенный захват в регулярном выражении с помощью c ++ [duplicate]

Никто не предоставил « классическое решение Reflection », так что вот полный пример кода:

using System;
using System.Collections;
using System.Collections.Generic;

namespace DictionaryRuntime
{
    public class DynamicDictionaryFactory
    {
        /// <summary>
        /// Factory to create dynamically a generic Dictionary.
        /// </summary>
        public IDictionary CreateDynamicGenericInstance(Type keyType, Type valueType)
        {
            //Creating the Dictionary.
            Type typeDict = typeof(Dictionary<,>);

            //Creating KeyValue Type for Dictionary.
            Type[] typeArgs = { keyType, valueType };

            //Passing the Type and create Dictionary Type.
            Type genericType = typeDict.MakeGenericType(typeArgs);

            //Creating Instance for Dictionary<K,T>.
            IDictionary d = Activator.CreateInstance(genericType) as IDictionary;

            return d;

        }
    }
}

Выше DynamicDictionaryFactory класс имеет метод

CreateDynamicGenericInstance(Type keyType, Type valueType)

, и он создает и возвращает экземпляр IDictionary, типы ключей и значений которых точно указаны в запросе keyType и valueType.

Вот полный пример того, как вызвать этот метод для создания экземпляра и использования Dictionary<String, int>:

using System;
using System.Collections.Generic;

namespace DynamicDictionary
{
    class Test
    {
        static void Main(string[] args)
        {
            var factory = new DictionaryRuntime.DynamicDictionaryFactory();
            var dict = factory.CreateDynamicGenericInstance(typeof(String), typeof(int));

            var typedDict = dict as Dictionary<String, int>;

            if (typedDict != null)
            {
                Console.WriteLine("Dictionary<String, int>");

                typedDict.Add("One", 1);
                typedDict.Add("Two", 2);
                typedDict.Add("Three", 3);

                foreach(var kvp in typedDict)
                {
                    Console.WriteLine("\"" + kvp.Key + "\": " + kvp.Value);
                }
            }
            else
                Console.WriteLine("null");
        }
    }
}

. Когда указанное консольное приложение выполняется, мы получаем правильный ожидаемый результат:

Dictionary<String, int>
"One": 1
"Two": 2
"Three": 3
100
задан Piku 12 December 2009 в 23:21
поделиться

19 ответов

#include <vector>
#include <string>
#include <sstream>
#include <iostream>

int main()
{
    std::string str = "1,2,3,4,5,6";
    std::vector<int> vect;

    std::stringstream ss(str);

    int i;

    while (ss >> i)
    {
        vect.push_back(i);

        if (ss.peek() == ',')
            ss.ignore();
    }

    for (i=0; i< vect.size(); i++)
        std::cout << vect.at(i)<<std::endl;
}
119
ответ дан 4 revs, 3 users 45% 18 August 2018 в 14:41
поделиться
  • 1
    Я думаю, что это не удастся, если перед пробелом есть пробелы, – KeithB 13 December 2009 в 00:09
  • 2
    да это будет, но пробелы не были частью первоначальной проблемы – user229321 13 December 2009 в 00:12
  • 3
    Чтобы охватить это: if (ss.peek() == ',' || ss.peek() == ' ') – safe_malloc 31 October 2014 в 10:27
  • 4
    Как его изменить, если вы хотите получить значения в массиве? (Если количество элементов уже известно) – S.Dan 10 November 2014 в 13:22
  • 5
    @safe_malloc: Shoudnt это будет while (ss.peek() == ',' || ss.peek() == ' ') – saurabheights 10 May 2016 в 16:30

Еще один, довольно отличный подход: используйте специальную локаль, которая обрабатывает запятые как пробел:

#include <locale>
#include <vector>

struct csv_reader: std::ctype<char> {
    csv_reader(): std::ctype<char>(get_table()) {}
    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());

        rc[','] = std::ctype_base::space;
        rc['\n'] = std::ctype_base::space;
        rc[' '] = std::ctype_base::space;
        return &rc[0];
    }
}; 

Чтобы использовать это, вы imbue() поток с локалием, который включает этот грань. Как только вы это сделаете, вы можете читать цифры, как будто запятые не были там вообще. Например, мы будем считывать номера с разделителями-запятыми из ввода и записывать затем одну строку на стандартный вывод:

#include <algorithm>
#include <iterator>
#include <iostream>

int main() {
    std::cin.imbue(std::locale(std::locale(), new csv_reader()));
    std::copy(std::istream_iterator<int>(std::cin), 
              std::istream_iterator<int>(),
              std::ostream_iterator<int>(std::cout, "\n"));
    return 0;
}
54
ответ дан 2 revs 18 August 2018 в 14:41
поделиться
  • 1
    Самый творческий ответ, который я когда-либо видел! – yoco 16 May 2011 в 17:37
  • 2
    +1, используя только std, и это чистое и простое решение. Не заглядывать и игнорировать символы! – kravemir 23 February 2013 в 16:30
  • 3
    Вот рабочий пример, если кто-то захотел попробовать: ideone.com/RX5o10 – kravemir 23 February 2013 в 16:40
  • 4
    обратите внимание, что приведенный выше пример будет взрываться, если ввод выглядит как «1, 2, 3, 4, 5 ...». вам нужно добавить строку rc [''] = ctype_base :: space ;. Принял меня немного, чтобы понять это – aCuria 27 March 2013 в 21:35
  • 5
    Я боюсь, что это решение не поддерживает пустую строку, но они просто будут пропущены. Возьмем, к примеру, этот вход: 1,2,3,,5,6,7. – Fabio A. 24 September 2015 в 08:20

Библиотека инструментов C ++ String Toolkit Library (Strtk) имеет следующее решение вашей проблемы:

#include <string>
#include <deque>
#include <vector>
#include "strtk.hpp"
int main()
{ 
   std::string int_string = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15";
   std::vector<int> int_list;
   strtk::parse(int_string,",",int_list);

   std::string double_string = "123.456|789.012|345.678|901.234|567.890";
   std::deque<double> double_list;
   strtk::parse(double_string,"|",double_list);

   return 0;
}

Можно найти другие примеры Здесь

43
ответ дан 2 revsMatthieu N. 18 August 2018 в 14:41
поделиться
std::string input="1,1,1,1,2,1,1,1,0";
std::vector<long> output;
for(std::string::size_type p0=0,p1=input.find(',');
        p1!=std::string::npos || p0!=std::string::npos;
        (p0=(p1==std::string::npos)?p1:++p1),p1=input.find(',',p0) )
    output.push_back( strtol(input.c_str()+p0,NULL,0) );

Было бы неплохо проверить ошибки преобразования в strtol(), конечно. Возможно, код может также помочь в некоторых других проверках ошибок.

5
ответ дан 3 revs 18 August 2018 в 14:41
поделиться
  • 1
    Какой беспорядок! Вам не нужно класть все на одну линию. – Timmmm 15 February 2018 в 13:04
  • 2
    @Timmmm, и вам не нужно рассказывать, что мне не нужно делать, вы не вынуждены использовать этот код, не так ли? – Michael Krelin - hacker 15 February 2018 в 16:32
  • 3
    Извините, я не хотел оскорблять - просто предложение о том, что вы можете сделать свой код намного понятнее, если вы немного разобьете его, и у вас меньше шансов пропустить ошибки. Я не вынужден использовать его, но это не значит, что я не могу выразить свое мнение. В этом весь смысл системы голосования SO. – Timmmm 15 February 2018 в 16:58
  • 4
    @Timmmm, конечно, вы можете, и я полностью согласен с вашим мнением, отличным от моего. Я лично нахожу значение в сжатом коде точно , потому что его легче читать, хотя с точки зрения строк за единицу времени он медленнее. Я также осознаю, что это вид my , и другие люди видят его по-другому. Я честно считаю, что их код беспорядок, но воздержитесь от его указания :) – Michael Krelin - hacker 15 February 2018 в 20:34

Что-то менее подробное, std и принимает что-либо, разделенное запятой.

stringstream ss( "1,1,1,1, or something else ,1,1,1,0" );
vector<string> result;

while( ss.good() )
{
    string substr;
    getline( ss, substr, ',' );
    result.push_back( substr );
}
72
ответ дан 3 revs, 2 users 81% 18 August 2018 в 14:41
поделиться
  • 1
    Ошибка в последней строке вашего кода. result.push_back(substr);;) – eouti 11 July 2012 в 13:03
  • 2
    Это отлично поработало для меня. очень мало строк кода, и он отлично работает. – mauricioSanchez 3 December 2014 в 21:36
  • 3
    Легко читается и отлично справляется с пробелами. Благодаря! – sudo make install 22 September 2015 в 11:02
  • 4
    Простая, легко читаемая, не требует специальной библиотеки! – Johan Engblom 5 November 2015 в 14:58
  • 5
    Обратите внимание, что для пустой строки это все равно сделает result.push_back("");, что, вероятно, не то, что вы хотите. – Timmmm 29 August 2017 в 10:58

Я еще не могу прокомментировать (начало работы на сайте), но добавил более общую версию производного класса Джерри Коффина в класс. К тому же

Спасибо Джерри за супер идею.

(потому что он должен быть проверен экспертами, добавив его здесь слишком временно)

struct SeparatorReader: std::ctype<char>
{
    template<typename T>
    SeparatorReader(const T &seps): std::ctype<char>(get_table(seps), true) {}

    template<typename T>
    std::ctype_base::mask const *get_table(const T &seps) {
        auto &&rc = new std::ctype_base::mask[std::ctype<char>::table_size]();
        for(auto &&sep: seps)
            rc[static_cast<unsigned char>(sep)] = std::ctype_base::space;
        return &rc[0];
    }
};
1
ответ дан 3 revs, 2 users 96% 18 August 2018 в 14:41
поделиться

Простая функция копирования / вставки, основанная на токенизаторе .

void strToIntArray(std::string string, int* array, int array_len) {
  boost::tokenizer<> tok(string);
  int i = 0;
  for(boost::tokenizer<>::iterator beg=tok.begin(); beg!=tok.end();++beg){
    if(i < array_len)
      array[i] = atoi(beg->c_str());
    i++;
}
0
ответ дан Daniel Eckert 18 August 2018 в 14:41
поделиться
void ExplodeString( const std::string& string, const char separator, std::list<int>& result ) {
    if( string.size() ) {
        std::string::const_iterator last = string.begin();
        for( std::string::const_iterator i=string.begin(); i!=string.end(); ++i ) {
            if( *i == separator ) {
                const std::string str(last,i);
                int id = atoi(str.c_str());
                result.push_back(id);
                last = i;
                ++ last;
            }
        }
        if( last != string.end() ) result.push_back( atoi(&*last) );
    }
}
-1
ответ дан Frunsi 18 August 2018 в 14:41
поделиться
#include <sstream>
#include <vector>
#include <algorithm>
#include <iterator>

const char *input = ",,29870,1,abc,2,1,1,1,0";
int main()
{
    std::stringstream ss(input);
    std::vector<int> output;
    int i;
    while ( !ss.eof() )
    {
       int c =  ss.peek() ;
       if ( c < '0' || c > '9' )
       {
          ss.ignore(1);
          continue;
        }

       if (ss >> i)
       {
          output.push_back(i);
        }

    }

    std::copy(output.begin(), output.end(), std::ostream_iterator<int> (std::cout, " ") );
    return 0;
}
-4
ответ дан greatoakhe 18 August 2018 в 14:41
поделиться
bool GetList (const std::string& src, std::vector<int>& res)
  {
    using boost::lexical_cast;
    using boost::bad_lexical_cast;
    bool success = true;
    typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
    boost::char_separator<char> sepa(",");
    tokenizer tokens(src, sepa);
    for (tokenizer::iterator tok_iter = tokens.begin(); 
         tok_iter != tokens.end(); ++tok_iter) {
      try {
        res.push_back(lexical_cast<int>(*tok_iter));
      }
      catch (bad_lexical_cast &) {
        success = false;
      }
    }
    return success;
  }
0
ответ дан KeithB 18 August 2018 в 14:41
поделиться

Вы также можете использовать следующую функцию.

void tokenize(const string& str, vector<string>& tokens, const string& delimiters = ",")
{
  // Skip delimiters at beginning.
  string::size_type lastPos = str.find_first_not_of(delimiters, 0);

  // Find first non-delimiter.
  string::size_type pos = str.find_first_of(delimiters, lastPos);

  while (string::npos != pos || string::npos != lastPos) {
    // Found a token, add it to the vector.
    tokens.push_back(str.substr(lastPos, pos - lastPos));

    // Skip delimiters.
    lastPos = str.find_first_not_of(delimiters, pos);

    // Find next non-delimiter.
    pos = str.find_first_of(delimiters, lastPos);
  }
}
6
ответ дан kiamlaluno 18 August 2018 в 14:41
поделиться
string exp = "token1 token2 token3";
char delimiter = ' ';
vector<string> str;
string acc = "";
for(int i = 0; i < exp.size(); i++)
{
    if(exp[i] == delimiter)
    {
        str.push_back(acc);
        acc = "";
    }
    else
        acc += exp[i];
}
1
ответ дан knapcio 18 August 2018 в 14:41
поделиться

Я удивлен, что никто не предложил решение с помощью std::regex еще:

#include <string>
#include <algorithm>
#include <vector>
#include <regex>

void parse_csint( const std::string& str, std::vector<int>& result ) {

    typedef std::regex_iterator<std::string::const_iterator> re_iterator;
    typedef re_iterator::value_type re_iterated;

    std::regex re("(\\d+)");

    re_iterator rit( str.begin(), str.end(), re );
    re_iterator rend;

    std::transform( rit, rend, std::back_inserter(result), 
        []( const re_iterated& it ){ return std::stoi(it[1]); } );

}

Эта функция вставляет все целые числа на обратной стороне входного вектора. Вы можете настроить регулярное выражение для включения отрицательных целых чисел или чисел с плавающей запятой и т. Д.

2
ответ дан Sheljohn 18 August 2018 в 14:41
поделиться
#include <sstream>
#include <vector>

const char *input = "1,1,1,1,2,1,1,1,0";

int main() {
    std::stringstream ss(input);
    std::vector<int> output;
    int i;
    while (ss >> i) {
        output.push_back(i);
        ss.ignore(1);
    }
}

Плохой ввод (например, последовательные разделители) испортит это, но вы сказали просто.

2
ответ дан Steve Jessop 18 August 2018 в 14:41
поделиться

Альтернативное решение с использованием общих алгоритмов и Boost.Tokenizer :

struct ToInt
{
    int operator()(string const &str) { return atoi(str.c_str()); }
};

string values = "1,2,3,4,5,9,8,7,6";

vector<int> ints;
tokenizer<> tok(values);

transform(tok.begin(), tok.end(), back_inserter(ints), ToInt());
17
ответ дан TC. 18 August 2018 в 14:41
поделиться
  • 1
    если вы используете Boost.Tokenizer, почему бы не заменить atoi на boost::lexical_cast? – Andriy Tylychko 10 February 2011 в 00:51

Здесь много ужасных ответов, поэтому я добавлю свою (включая тестовую программу):

#include <string>
#include <iostream>
#include <cstddef>

template<typename StringFunction>
void splitString(const std::string &str, char delimiter, StringFunction f) {
  std::size_t from = 0;
  for (std::size_t i = 0; i < str.size(); ++i) {
    if (str[i] == delimiter) {
      f(str, from, i);
      from = i + 1;
    }
  }
  if (from <= str.size())
    f(str, from, str.size());
}


int main(int argc, char* argv[]) {
    if (argc != 2)
        return 1;

    splitString(argv[1], ',', [](const std::string &s, std::size_t from, std::size_t to) {
        std::cout << "`" << s.substr(from, to - from) << "`\n";
    });

    return 0;
}

Хорошие свойства:

  • Нет зависимостей (например, boost)
  • Не безумный однострочный
  • Легко понять (надеюсь)
  • Управляет пространством отлично
  • Не выделяет разбиения если вы этого не хотите, например вы можете обрабатывать их с помощью лямбда, как показано на рисунке.
  • Не добавлять символы по одному - должно быть быстро.
  • Если вы используете C ++ 17, вы можете изменить его для использования a std::stringview, а затем он не будет выполнять никаких распределений и должен быть очень быстрым.

Некоторые варианты дизайна, которые вы, возможно, захотите изменить:

  • Пусто записи не игнорируются.
  • Пустая строка будет вызывать f () один раз.

Пример входов и выходов:

""      ->   {""}
","     ->   {"", ""}
"1,"    ->   {"1", ""}
"1"     ->   {"1"}
" "     ->   {" "}
"1, 2," ->   {"1", " 2", ""}
" ,, "  ->   {" ", "", " "}
3
ответ дан Timmmm 18 August 2018 в 14:41
поделиться

простая структура, легко адаптируемая, простая поддержка.

std::string stringIn = "my,csv,,is 10233478,separated,by commas";
std::vector<std::string> commaSeparated(1);
int commaCounter = 0;
for (int i=0; i<stringIn.size(); i++) {
    if (stringIn[i] == ",") {
        commaSeparated.push_back("");
        commaCounter++;
    } else {
        commaSeparated.at(commaCounter) += stringIn[i];
    }
}

, в конце вы будете иметь вектор строк с каждым элементом предложения, разделенным пробелами. пустые строки сохраняются как отдельные элементы.

0
ответ дан tony gil 18 August 2018 в 14:41
поделиться
0
ответ дан 2 revs 7 September 2018 в 00:44
поделиться
0
ответ дан 2 revs 30 October 2018 в 05:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: