форматирование std :: string как sprintf

string.split не поддерживается в LINQ-to-SQL.

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

var category = 
    _dataContext.Categories.ToList()
    .Where<Category>(p => p.Keywords.Split(' ').Contains<string>(context.Request.QueryString["q"])).First();

Вызов .ToList() заставит перечисление всех категорий из вашего источника данных, а последующие операции будут выполняться в клиентском коде.

396
задан thecoshman 9 May 2015 в 17:45
поделиться

8 ответов

Вы не можете сделать это напрямую, потому что у вас нет доступа на запись в базовый буфер (до C ++ 11; см. комментарий ). Вам нужно будет сначала сделать это в c-строке, а затем скопировать в std :: string:

  char buff[100];
  snprintf(buff, sizeof(buff), "%s", "Hello");
  std::string buffAsStdStr = buff;

Но я не уверен, почему бы вам просто не использовать строковый поток? Я предполагаю, что у вас есть особые причины не делать это просто так:

  std::ostringstream stringStream;
  stringStream << "Hello";
  std::string copyOfStr = stringStream.str();
303
ответ дан 22 November 2019 в 23:31
поделиться

Я попробовал, с регулярными выражениями . Я реализовал это для ints и const-строк в качестве примера, но вы можете добавить любые другие типы ( POD , но с помощью указателей вы можете печатать что угодно).

#include <assert.h>
#include <cstdarg>

#include <string>
#include <sstream>
#include <regex>

static std::string
formatArg(std::string argDescr, va_list args) {
    std::stringstream ss;
    if (argDescr == "i") {
        int val = va_arg(args, int);
        ss << val;
        return ss.str();
    }
    if (argDescr == "s") {
        const char *val = va_arg(args, const char*);
        ss << val;
        return ss.str();
    }
    assert(0); //Not implemented
}

std::string format(std::string fmt, ...) {
    std::string result(fmt);
    va_list args;
    va_start(args, fmt);
    std::regex e("\\{([^\\{\\}]+)\\}");
    std::smatch m;
    while (std::regex_search(fmt, m, e)) {
        std::string formattedArg = formatArg(m[1].str(), args);
        fmt.replace(m.position(), m.length(), formattedArg);
    }
    va_end(args);
    return fmt;
}

Вот пример использования этого:

std::string formatted = format("I am {s} and I have {i} cats", "bob", 3);
std::cout << formatted << std::endl;

Вывод:

Я Боб, и у меня есть 3 кошки

0
ответ дан Peter Mortensen 9 May 2015 в 17:45
поделиться

Здесь мое (простое решение):

std::string Format(const char* lpszFormat, ...)
{
    // Warning : "vsnprintf" crashes with an access violation
    // exception if lpszFormat is not a "const char*" (for example, const string&)

    size_t  nSize     = 1024;
    char    *lpBuffer = (char*)malloc(nSize);

    va_list lpParams;

    while (true)
    {
        va_start(lpParams, lpszFormat);

        int nResult = vsnprintf(
            lpBuffer,
            nSize,
            lpszFormat,
            lpParams
        );

        va_end(lpParams);

        if ((nResult >= 0) && (nResult < (int)nSize) )
        {
            // Success

            lpBuffer[nResult] = '\0';
            std::string sResult(lpBuffer);

            free (lpBuffer);

            return sResult;
        }
        else
        {
            // Increase buffer

            nSize =
                  (nResult < 0)
                ? nSize *= 2
                : (nResult + 1)
            ;

            lpBuffer = (char *)realloc(lpBuffer, nSize);
        }
    }
}
0
ответ дан Peter Mortensen 9 May 2015 в 17:45
поделиться

Похоже, что все ответы здесь до сих пор имеют одну или несколько из следующих проблем: (1) он может не работать на VC ++ (2) он требует дополнительных зависимостей, таких как boost или fmt (3), его слишком сложная пользовательская реализация и, вероятно, нет хорошо проверено.

Ниже приведен код для решения всех вышеперечисленных проблем.

#include <string>
#include <cstdarg>
#include <memory>

std::string stringf(const char* format, ...)
{
    va_list args;
    va_start(args, format);
    #ifndef _MSC_VER

        //GCC generates warning for valid use of snprintf to get
        //size of result string. We suppress warning with below macro.
        #ifdef __GNUC__
        #pragma GCC diagnostic push
        #pragma GCC diagnostic ignored "-Wformat-nonliteral"
        #endif

        size_t size = std::snprintf(nullptr, 0, format, args) + 1; // Extra space for '\0'

        #ifdef __GNUC__
        # pragma GCC diagnostic pop
        #endif

        std::unique_ptr<char[]> buf(new char[ size ] ); 
        std::vsnprintf(buf.get(), size, format, args);
        return std::string(buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
    #else
        int size = _vscprintf(format, args);
        std::string result(++size, 0);
        vsnprintf_s((char*)result.data(), size, _TRUNCATE, format, args);
        return result;
    #endif
    va_end(args);
}    

int main() {
    float f = 3.f;
    int i = 5;
    std::string s = "hello!";
    auto rs = stringf("i=%d, f=%f, s=%s", i, f, s.c_str());
    printf("%s", rs.c_str());
    return 0;
}

Примечания:

  1. Отдельная ветвь кода VC ++ необходима, потому что VC ++ решил отказаться от snprintf, который будет генерировать предупреждения компилятора для других ответов с высоким рейтингом выше. Поскольку я всегда работаю в режиме «предупреждения как ошибки», мне это не подходит.
  2. Функция принимает char * вместо std::string. Это потому, что большую часть времени эта функция вызывается с литеральной строкой, которая действительно char *, а не std::string. Если у вас есть std::string в качестве параметра формата, просто позвоните .c_str().
  3. Имя функции - stringf вместо таких вещей, как string_format для поддержки printf, scanf и т. Д.
  4. Это не решает проблему безопасности (то есть плохие параметры могут потенциально вызвать ошибку сегмента вместо исключения). Если вам это нужно, то лучше использовать библиотеки boost или fmt . Здесь я предпочитаю fmt, потому что это всего лишь один заголовок и исходный файл, который нужно добавить в проект, при этом синтаксис форматирования будет менее странным, чем boost. Однако оба они несовместимы со строками формата printf, поэтому ниже все равно полезно в этом случае.
  5. Код stringf проходит через компиляцию строгого режима GCC . Это требует дополнительных #pragma макросов для подавления ложных срабатываний в предупреждениях GCC.

Выше код был протестирован,

0
ответ дан Shital Shah 9 May 2015 в 17:45
поделиться

C++ 20 std::format

Это прибыло! Функция описана в: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0645r9.html и использование подобное Python .format() синтаксис.

я ожидаю, что использование будет похоже:

#include <format>
#include <string>

int main() {
    std::string message = std::format("The answer is {}.", 42);
}

я дам ему попытку, когда поддержка прибудет в GCC, GCC 9.1.0 с g++-9 -std=c++2a все еще не поддерживает его.

API добавит новое std::format заголовок:

предложенное форматирование API определяется в новом заголовке <format> и не должен оказывать влияние на существующий код.

существующее fmt библиотека утверждает, что реализовала его при необходимости в полизаливке: https://реализация github.com/fmtlib/fmt

C++ 20 std::format.

и был ранее упомянут в: станд.:: строка, форматирующая как sprintf

6
ответ дан 22 November 2019 в 23:31
поделиться

Если вам нужен синтаксис, подобный printf (без вызова printf самостоятельно), посмотрите Boost Format .

18
ответ дан 22 November 2019 в 23:31
поделиться

boost :: format () обеспечивает желаемую функциональность:

Согласно синопсису библиотек формата Boost:

Объект формата создается из строки формата, а затем ему передаются аргументы через повторение вызовы оператора%. Каждый из этих аргументов затем преобразуется в строки, которые, в свою очередь, объединяются в одну строку в соответствии со строкой формата.

#include <boost/format.hpp>

cout << boost::format("writing %1%,  x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
// prints "writing toto,  x=40.230 : 50-th try"
106
ответ дан 22 November 2019 в 23:31
поделиться

строка не имеет того, что вам нужно, но std :: stringstream есть. Используйте поток строк для создания строки, а затем извлеките строку. Здесь - полный список того, что вы можете делать. Например:

cout.setprecision(10); //stringstream is a stream like cout

даст вам 10 десятичных знаков точности при печати двойного или плавающего числа.

3
ответ дан 22 November 2019 в 23:31
поделиться
Другие вопросы по тегам:

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