Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,869
Записей в блоге: 2

Разбор строки

05.12.2025, 16:05. Показов 5954. Ответов 45
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день

Нужно разобрать (распарсить) такую строку
f 4904/74/6472 4842/76/6473 4848/75/6474
Это из популярного .obj файла, "f" - описание одного полигона (фейса). Каждая тройка чисел - индексы для позиции, UV и нормали вертекса соответственно. Число троек любое, фейс может ссылаться на любое число вертексов. Позиция есть всегда, UV и/или нормали могут отсутствовать, примеры
f 4904 4842 4848 ; только позиция
f 4904/74 4842/76 4848/75 ; позиция + UV
f 4904//6472 4842//6473 4848//6474 ; позиция + нормаль
Для простоты считаем что на выходе должны получить такую структуру
C++
1
2
3
struct Face {
 std::vector<int> m_pos, m_uv, m_normal;
};
Есть лучшие предложения по организации данных - с удовольствием послушаю.
Требования к разбору: юникод здесь не актуален (считаем что только латинский текст). Никакого копирования данных строки. Наверно бум юзать std::string_view, мы ведь его так любим (во всяком случае хвалим). Возможно первое что приходит в голову - использовать std::istringstream. Но ведь (я слышал) он deprecated? И как подружить его с std::string_view?

Спасибо
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
05.12.2025, 16:05
Ответы с готовыми решениями:

Разбор аргументов командной строки
Для Unix существуют специальные средства для разбора опций командной строки (функции GNU getopt и...

Разбор строки
Доброго времени суток. Прошу Вашей помощи в этом казалось бы не сложном деле. Не так давно пишу на...

Разбор строки из консоли и вопрос по g++
Всем доброго времени суток :) Недавно начал изучать C++ Вот есть пару вопросов... Первое -...

45
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6189 / 2891 / 1042
Регистрация: 01.06.2021
Сообщений: 10,607
05.12.2025, 20:07
Igor3D, я нашел в инете парсер для obj файлов и если копаться в реализации, то там все держится на одной функции, которая разбивает строку.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
std::vector<std::string_view>
StringUtils::splitString(const std::string& str, const std::initializer_list<const char> delimiters)
{
    std::function delimiterCheck(&isblank);
    if (delimiters.size() > 0)
    {
        delimiterCheck = [&delimiters](const auto chr) {
            return (isblank(chr) != 0) ||
                   (std::find(delimiters.begin(), delimiters.end(), chr) != delimiters.end());
        };
    }
 
    auto startItr = str.cbegin();
    auto splitItr = startItr;
    std::vector<std::string_view> subStrings;
 
    while ((splitItr = std::find_if(startItr, str.cend(), delimiterCheck)) != str.cend())
    {
        if (delimiterCheck(*startItr) == false)
        {
            subStrings.push_back(std::string_view(&*startItr, std::distance(startItr, splitItr)));
        }
        startItr = splitItr + 1;
    }
 
    if (startItr != str.cend())
    {
        subStrings.push_back(std::string_view(&*startItr, std::distance(startItr, str.cend())));
    }
 
    return subStrings;
}
2
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,058
05.12.2025, 21:19
Цитата Сообщение от Igor3D Посмотреть сообщение
std::istringstream. Но ведь (я слышал) он deprecated
я такого не слышал, живёт и здравствует.

Но в данном случае неэффективен из-за того, что будет дополнительная копия исходной строки.


в общем, если я идею правильно понял, то у меня вот так получилось
https://onlinegdb.com/IMH5LdkaIA

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <vector>
#include <optional>
#include <charconv>
 
struct Face
{
    std::vector<int> m_pos, m_uv, m_normal;
};
 
auto Parse(std::string_view src)
{
    std::vector<Face> list;
    
    auto extractNum=[&src]()->std::optional<unsigned long>
    {
        unsigned long n;
        auto [end,ec]=std::from_chars(src.data(),src.data()+src.size(),n);
        if(ec==std::errc{})
        {
            src.remove_prefix(end-src.data());
            return n;
        }
        return std::nullopt;
    };
    
    while(1)
    {
        Face f;
 
        auto pos_f=src.find('f');
        if(pos_f==src.npos)break;
        src.remove_prefix(pos_f+1);
        
        while(1)
        {
            if(src.empty() || src[0]!=' ')break;
            src.remove_prefix(1);
            
            if(auto n=extractNum()){f.m_pos.push_back(*n);}
            if(src.empty())break;
            if(src[0]==' ')continue;
            if(src[0]!='/')break;
            src.remove_prefix(1);
            
            if(auto n=extractNum()){f.m_uv.push_back(*n);}
            if(src.empty())break;
            if(src[0]==' ')continue;
            if(src[0]!='/')break;
            src.remove_prefix(1);
            
            if(auto n=extractNum()){f.m_normal.push_back(*n);}
            if(src.empty())break;
        }
        
        list.push_back(std::move(f));
    }
    
    return list;
}
 
int main()
{
    auto list=Parse(R"(
f 4904/74/6472 4842/76/6473 4848/75/6474
f 4904/74/ 4842/76/ 4848/75/
f 4904/74 4842/76 4848/75
f 4904//6472 4842//6473 4848//6474
)");
 
    for(auto& f:list)
    {
        std::cout<<"face"<<&f-list.data()<<'\n';
        
        std::cout<<"m_pos : ";
        for(auto n : f.m_pos){std::cout<<n<<',';}
        std::cout<<'\n';
        
        std::cout<<"m_uv : ";
        for(auto n : f.m_uv){std::cout<<n<<',';}
        std::cout<<'\n';
        
        std::cout<<"m_normal : ";
        for(auto n : f.m_normal){std::cout<<n<<',';}
        std::cout<<'\n';
        
        std::cout<<"------------\n";
    }
}
face0
m_pos : 4904,4842,4848,
m_uv : 74,76,75,
m_normal : 6472,6473,6474,
------------
face1
m_pos : 4904,4842,4848,
m_uv : 74,76,75,
m_normal :
------------
face2
m_pos : 4904,4842,4848,
m_uv : 74,76,75,
m_normal :
------------
face3
m_pos : 4904,4842,4848,
m_uv :
m_normal : 6472,6473,6474,
------------
2
Модератор
Эксперт Java
 Аватар для alecss131
2856 / 1363 / 406
Регистрация: 11.08.2017
Сообщений: 4,351
Записей в блоге: 2
05.12.2025, 22:39
Цитата Сообщение от Royal_X Посмотреть сообщение
нашел в инете парсер для obj файлов
Как по мне более популярная реализация, хотя я и не люблю этот формат
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6189 / 2891 / 1042
Регистрация: 01.06.2021
Сообщений: 10,607
06.12.2025, 01:38
alecss131, obj простенький формат, засунуть туда много чего нельзя. Грубо говоря, он подходит только для хранения меша и его uv и нормалей. Даже материалы нельзя засунуть. Дело в том, что внутри obj можно засунуть только ссылку на mtl файл (это формат-компаньон), который в свою очередь может хранить только банальные свойства материалов, а всякие текстуры засунуть не получится, тоже придется по ссылке. Mtl вообще устарел.
Единственное преимущество obj/mtl это то, что это открытый формат.

Наверняка ты предпочитаешь fbx. Но это проприетарный закрытый (но есть открытая реализация, полученная посредством реверс-инжиниринга) гнусный формат, хотя он популярен и активно пропагандируется всем коммерческим софтом, в том числе стандартами отрасли.

Я ещё иногда использую gltf / glb. Это тоже свободный формат от Khronos Group. Мне нравится, что в него можно засунуть даже текстуры (изображения), скелеты, анимации и все прочее.

Для 3д печати ещё встречал форматы 3mf, stl, ply...
0
Модератор
Эксперт Java
 Аватар для alecss131
2856 / 1363 / 406
Регистрация: 11.08.2017
Сообщений: 4,351
Записей в блоге: 2
06.12.2025, 15:15
Цитата Сообщение от Royal_X Посмотреть сообщение
gltf / glb
Для него библиотек не находил и он внутри довольно запутанный, хоть и позиционируется на основе графических апи, то есть максимально к ним приближенный по структуре, но на примере OpenGL он не близок. Это по сути стандарт, а в файлы пишет кто как умеет, нету так сказать реализации. У меня для его создания в коде вечно каша и легко все разрушить. В формате слишком много избыточных данных и всяких описателей, что где как и зачем на каждый чих.
Obj мне не нравится в первую очередь что он текстовый, будет весить больше чем бинарный, при этом теряя точность. И у него вечно непонятки с десятичными символами, то ли запятые то ли точки, вечно путаю. А еще нумерация вершин в индексах с 1.
Fbx я люблю только экспортировать в него из кода, хотя читать не сложнее. Некоторые вещи у него тоже не логичны, но есть сдк готовый и меня все устраивает, некоторые вещи довольно просто делаются (например анимации). В него можно засунуть и камеры и источники освещения и даже звуки, но вот материалы он поддерживает только простейший блинн-фонг, никаких pbr, что при импорте в ue например создает некорректные материалы.
Цитата Сообщение от Igor3D Посмотреть сообщение
Каждая тройка чисел
Формат поддерживает не только треугольники,а многоугольники.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6189 / 2891 / 1042
Регистрация: 01.06.2021
Сообщений: 10,607
06.12.2025, 15:29
alecss131, честно говоря, мне не нужны библиотеки для obj и мне плевать на его размер. Я их использую в играх, и игровые движки по-своему оптимизируют меши - не так, чтобы человеку было удобно, а так, чтобы gpu кайфовал.
0
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,869
Записей в блоге: 2
06.12.2025, 20:04  [ТС]
Цитата Сообщение от Royal_X Посмотреть сообщение
там все держится на одной функции, которая разбивает строку.
Это по сути реализация "split" (см напр QString::split), только разбивается на string_view вместо (затратных) подстрок. Все-таки затраты (пусть небольшие) на контейнер остаются. Начинающие такие ф-ции любят, выглядит очень привлекательно. Сначала разбиваем на стартовый "f" и тройки (разделитель пробел(ы)), потом каждую тройку на 3 числа (разделитель слеш). К сожалению, не все так просто
Цитата Сообщение от Igor3D Посмотреть сообщение
f 4904/74 4842/76 4848/75 ; позиция + UV
f 4904//6472 4842//6473 4848//6474 ; позиция + нормаль
Сплит даст одинаковый рез-т, а это не так
Цитата Сообщение от Алексей1153 Посмотреть сообщение
у меня вот так получилось
Это типа "по одной не ошибешься"? Во-первых, такое
f 4904/74/ 4842/76/ 4848/75/
проходить не должно. Во-вторых, надо что-то делать с ошибками, хотя бы их выдавать юзверю, а то у Вас парсер просто молотит дальше. Инициатива читать неск полигонов (отказ от построчной работы) неуместна. Ну и сравнение с пробелом неприятно режет глаз. Табы (и др гадость) никто не отменял, надо юзать isspace. И никто не обещал что пробелов/спейсов будет ровно один. Напр, насколько помню, from_chars стартовые пробелы не пропускает, если после "f" два пробелы - не проверял но могут быть неприятности

Несмотря на эти помарки, оба ответа содержательны и полезны, спасибо

Цитата Сообщение от alecss131 Посмотреть сообщение
Как по мне более популярная реализация, хотя я и не люблю этот формат
Ну (шкурной) задачи "где взять готовый ридер" не ставилось, хотелось пошлифовать логику разбора, лучше это делать на простом и (многим) знакомом примере
Цитата Сообщение от alecss131 Посмотреть сообщение
Формат поддерживает не только треугольники,а многоугольники.
Да, о чем сказано в стартовом посте. В связи с этим вопрос: а как рекомендованный Вами парсер решает проблему "комплексных полигонов" (с числом вертексов > 4)?
0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,058
06.12.2025, 20:43
Цитата Сообщение от Igor3D Посмотреть сообщение
проходить не должно. Во-вторых, надо что-то делать с ошибками, хотя бы их выдавать юзверю
это уже самостоятельно.

Цитата Сообщение от Igor3D Посмотреть сообщение
Инициатива читать неск полигонов (отказ от построчной работы) неуместна
а что так ?

Цитата Сообщение от Igor3D Посмотреть сообщение
Ну и сравнение с пробелом неприятно режет глаз. Табы (и др гадость) никто не отменял
в условии про это ничего не сказано было
0
Just Do It!
 Аватар для XLAT
4204 / 2662 / 654
Регистрация: 23.09.2014
Сообщений: 9,058
Записей в блоге: 3
06.12.2025, 22:18
1.
Цитата Сообщение от alecss131 Посмотреть сообщение
мне не нравится в первую очередь что он текстовый
зачем он текстовый?
чтобы модель можно было экспортировать под любую платформу, под любой драйвер, под любую железку...
аналогия: как язык Си, а не ассемблер(аналог бинарной модели).

2.
мой вар простой, без изысков, то что нужно для раздела С++ для начинающих:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/// DEMO Obj Loader.
///----------------------------------------------------------------------------|
/// C++20
/// source code: UTF-8
/// https://ru.wikipedia.org/wiki/Obj
///----------------------------------------------------------------------------|
#include <iostream>
#include <sstream>
#include <vector>
#include <format>
 
#define l(a) std::cout << #a << " = " << (a) << '\n';
 
template <typename... TT> void Banner(TT&&... vals)
{   ((std::cout << vals << std::endl), ...);
}
 
///----------------------------------------------------------------------------|
/// Генератор входных данных.
///-------------------------------------------------------------------- GenTest:
struct GenTest
{
    static std::string get(int n = 1)
    {
        constexpr const char* ss
        {
            "f 49.04 484.2 4.848 ; только позиция\n"
            "f 4904/74 4842/76 4848/75 ; позиция + UV\n"
            "f 4904//6472 4842//6473 4848//6474 ; позиция + нормаль\n"
        };
 
        std::string s;
        while (n--) s += ss;
        return      s;
    }
};
 
///----------------------------------------------------------------------------|
/// Грань.
///----------------------------------------------------------------------- Face:
struct Face : std::array<std::vector<float>, 3>
{
    enum EFACE
    {   POS,
        UV,
        NORM
    };
};
 
std::ostream& operator<<(std::ostream& o, const Face& f)
{   o << "pos : "; for(const auto n : f[Face::POS ]) {o << n << ' ';} o << '\n';
    o << "uv  : "; for(const auto n : f[Face::UV  ]) {o << n << ' ';} o << '\n';
    o << "norm: "; for(const auto n : f[Face::NORM]) {o << n << ' ';} o << '\n';
    return o;
}
 
///----------------------------------------------------------------------------|
/// ObjLoader
///------------------------------------------------------------------ ObjLoader:
struct  ObjLoader : Face
{       ObjLoader()
        {
        }
 
    void go(std::istream&& is)
    {
        size_t cnt{};
 
        for(std::string s; std::getline(is, s); ++cnt)
        {
            if(s[0] != 'f') continue;
 
            for(std::stringstream is(s); std::getline(is, s, ' ');)
            {   if(s[0] == 'f') continue;
                if(s[0] == ';') break;
 
                size_t i{};
                size_t d  ;
 
                for(std::stringstream is(s); std::getline(is, s, '/'); ++i)
                {
                    if(i > 2    ) throw(cnt);
                    if(s.empty()) continue  ;
 
                    (*this)[cnt].push_back(std::stod(s, &d));
                    if(d != s.size()) throw(cnt);
                }
            }
        }
    }
 
    static void test()
    {
        try
        {   ObjLoader    objLoader;
                         objLoader.go(std::stringstream(GenTest::get()));
            std::cout << objLoader << '\n';
        }
        catch(size_t cnt)
        {   std::cout << std::format("ERROR: ObjLoader str={}...\n\n", cnt);
            return;
        }
 
        Banner(
        "///--------------------------|",
        "/// Тестирование УСПЕШНО!    |",
        "///--------------------------|\n");
    }
 
private:
};
 
///----------------------------------------------------------------------------|
/// main
///----------------------------------------------------------------------- main:
int main()
{
/// std::setlocale(0,      "");
/// std::setlocale(LC_ALL, "ru_RU.UTF-8");
    std::system        (  "chcp 65001>0");
    std::locale::global(std::locale("C"));
 
    Banner(
        "///--------------------------------|",
        "/// Привет, я есть OBJ-LOADER!     |",
        "///--------------------------------|\n");
 
    ObjLoader::test();
 
    std::cout << "ПРОГРАММА ЗАВЕРШИЛА РАБОТУ." << std::endl;
}
3.
код бы получился более красивше,
если ваще не заботиться об ошибках в тексте модели,
но в минимуме я всё же позаботился.
хз нужно ли?

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

5.
Цитата Сообщение от Igor3D Посмотреть сообщение
Есть лучшие предложения по организации данных - с удовольствием послушаю.
есть предложение завязывать с лоу-кодингом на велосипедах,
и начинать вертеть системами с целью захапать сразу лям $.

вот
Цитата Сообщение от Royal_X Посмотреть сообщение
мне не нужны библиотеки для obj
есть со мной согласные)
0
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,869
Записей в блоге: 2
06.12.2025, 22:37  [ТС]
Цитата Сообщение от Алексей1153 Посмотреть сообщение
это уже самостоятельно.
То есть работа с ошибками - мелочь, любой начинающий сам ее сделает? Не согласен, наоборот, здесь нужен высокий класс. Ну да ладно, поговорим о принципиальном. Вот выше приведена ф-ция splitString разбивающая строку на токены. Заметьте что вопросов как разобрать строку уже не возникает, это выглядит как-то так, псевдокод
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
auto sub = splitString(src, isspace); 
if (!sub.size()) continue;
if (sub[0] == 'f')) {
 Face face;
 for (size_t i = 1; i < sub.size(); ++i) {
  auto attr = splitString(sub[i], '/'); 
  face.m_position.push_back(ReadInt(attr[0]);
  if (attr.size() > 1) 
   face.m_uv.push_back(ReadInt(attr[1]));
  if (attr.size() > 2) 
   face.m_normal.push_back(ReadInt(attr[2]));
 }
 faces.push_back(face);
}
 
if (sub[0] == 'v')) {
 Vec3f pos;
 assert(sub.size() == 4);
 pos.x = ReadFloat(sub[1]);
 pos.y = ReadFloat(sub[2]);
 pos.z = ReadFloat(sub[3]);
 vertices.push_back(pos);
}
 
if (sub[0] == "vn")) {
 ...
Заметьте как гладко, очевидно, не затрудняя дыхание и.т.п. идет дальнейший разбор. А у Вас? Куча логики, проверок, везде надо думать. Да, сейчас "работает", не спорю. Но стоит чему-то измениться - и все, капец. Ясно нужна какая-то "концепция" (не побоюсь этого слова) чтобы не париться с разбором всякий раз. Причем необязательно сплиттить..
0
Just Do It!
 Аватар для XLAT
4204 / 2662 / 654
Регистрация: 23.09.2014
Сообщений: 9,058
Записей в блоге: 3
07.12.2025, 00:18
Цитата Сообщение от Igor3D Посмотреть сообщение
такое
f 4904/74/ 4842/76/ 4848/75/
проходить не должно.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/// DEMO Obj Loader.
///----------------------------------------------------------------------------|
/// C++20
/// source code: UTF-8
/// https://ru.wikipedia.org/wiki/Obj
///----------------------------------------------------------------------------|
#include <iostream>
#include <sstream>
#include <vector>
#include <format>
 
#define l(a) std::cout << #a << " = " << (a) << '\n';
 
template <typename... TT> void Banner(TT&&... vals)
{   ((std::cout << vals << std::endl), ...);
}
 
///----------------------------------------------------------------------------|
/// Генератор входных данных.
///-------------------------------------------------------------------- GenTest:
struct GenTest
{
    static std::string get(int n = 1)
    {
        constexpr const char* ss
        {
            "f\t-11.22      484.2        4.848   ; только позиция\n"
            "f\t4904/-74   4842/76      4848/75  ; позиция + UV\n"
            "f -4904//6472 4842//-6473  4848//64 ; позиция + нормаль\n"
            "f -49/04/6472 48/-42/-6473 77/88/99 ;"
        };
 
        std::string s;
        while (n--) s += ss;
        return      s;
    }
};
 
///----------------------------------------------------------------------------|
/// Грань.
///----------------------------------------------------------------------- Face:
struct Face : std::array<std::vector<float>, 3>
{
    enum EFACE
    {   POS,
        UV,
        NORM
    };
};
 
std::ostream& operator<<(std::ostream& o, const Face& f)
{   o << "pos : "; for(const auto n : f[Face::POS ]) {o << n << ' ';} o << '\n';
    o << "uv  : "; for(const auto n : f[Face::UV  ]) {o << n << ' ';} o << '\n';
    o << "norm: "; for(const auto n : f[Face::NORM]) {o << n << ' ';} o << '\n';
    return o;
}
 
///----------------------------------------------------------------------------|
/// ObjLoader
///------------------------------------------------------------------ ObjLoader:
struct  ObjLoader : Face
{       ObjLoader()
        {
        }
 
    void go(std::istream&& is)
    {
        size_t cnt{};
 
        for(std::string s; std::getline(is, s); ++cnt)
        {
            if(s[0] != 'f') continue;
 
            for(std::stringstream is(s); is >> s;)
            {   if(s[0] == 'f') continue;
                if(s[0] == ';') break;
 
                size_t i{};
                size_t d  ;
 
                if(!std::isdigit(s.back())) throw(cnt);
 
                for(std::stringstream is(s); std::getline(is, s, '/'); ++i)
                {
                    if(i > 2)              throw(cnt);
                    if(s.empty()&& i == 1) continue  ;
 
                    try
                    {   (*this)[i].push_back(std::stod(s, &d));
                        if(d != s.size()) throw(cnt);
                    }
                    catch(...){ throw(cnt); }
                }
            }
        }
    }
 
    static void test()
    {
        try
        {   ObjLoader    objLoader;
                         objLoader.go(std::stringstream(GenTest::get()));
            std::cout << objLoader << '\n';
        }
        catch(size_t cnt)
        {   std::cout << std::format("ERROR: ObjLoader line={}...\n\n", cnt);
            return;
        }
 
        Banner(
        "///--------------------------|",
        "/// Тестирование УСПЕШНО!    |",
        "///--------------------------|\n");
    }
 
private:
};
 
///----------------------------------------------------------------------------|
/// main
///----------------------------------------------------------------------- main:
int main()
{
    std::system        (  "chcp 65001>0");
    std::locale::global(std::locale("C"));
 
    Banner(
        "///--------------------------------|",
        "/// Привет, я есть OBJ-LOADER!     |",
        "///--------------------------------|\n");
 
    ObjLoader::test();
 
    std::cout << "ПРОГРАММА ЗАВЕРШИЛА РАБОТУ." << std::endl;
}
выхлоп:
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
///--------------------------------|
/// Привет, я есть OBJ-LOADER!     |
///--------------------------------|
 
pos : -11.22 484.2 4.848 4904 4842 4848 -4904 4842 4848 -49 48 77
uv  : -74 76 75 4 -42 88
norm: 6472 -6473 64 6472 -6473 99
 
///--------------------------|
/// Тестирование УСПЕШНО!    |
///--------------------------|
 
ПРОГРАММА ЗАВЕРШИЛА РАБОТУ.
0
1968 / 824 / 115
Регистрация: 01.10.2012
Сообщений: 4,869
Записей в блоге: 2
07.12.2025, 04:36  [ТС]
Цитата Сообщение от XLAT Посмотреть сообщение
C++
1
struct Face : std::array<std::vector<float>, 3>
int (вместо float), это индексы. На мой взгляд, массив здесь - нездоровая затея. Лучше потратить пару строк но видеть какие данные читаются. И вообще подгонять структуры под ф-ции нехорошо. Также чтение не стоит оформлять методом Face (как операторы I/O не методы)
Цитата Сообщение от XLAT Посмотреть сообщение
for(std::stringstream is(s); std::getline(is, s, '/'); ++i)
Даже если можно использовать s "там и сям" - это совершенно напрасный трюк
Цитата Сообщение от XLAT Посмотреть сообщение
мой вар простой, без изысков, то что нужно для раздела С++ для начинающих:
Ну как... Согласен, getline() совсем не плохо. Но если уж мы "не гонимся за модой", то почему бы не использовать sscanf? Или strtol еще лучше, удачно подхватывается символ на котором остановится. Это не будет сильно длиннее, да и по скорости без проблем. А то совсем недавно мы дружно аплодировали std::string_view, но дошло до дела - почему-то ныряем в getline да еще и в deprecated stringstream.

Заметим что во всех случаях есть какая-то "ударная" ф-ция которая делает что нужно, и код группируется возле нее.

Не по теме:

Цитата Сообщение от XLAT Посмотреть сообщение
хотца ... моно
Переход на "жаргон босяка" обычно говорит о неуверенности :)

0
фрилансер
 Аватар для Алексей1153
6454 / 5655 / 1129
Регистрация: 11.10.2019
Сообщений: 15,058
07.12.2025, 08:41
Цитата Сообщение от Igor3D Посмотреть сообщение
Но стоит чему-то измениться - и все, капец.
нужно разобраться, на что делается упор - воздушность кода или эффективность?
Я ж задавал вопрос - как часто и в каком количестве это всё разбирается ?

Если единожды перед запуском игры - то берём строковый поток, ждём 5 секунд и всё в шоколаде.
Если нужна молотилка - это как у меня. Изменение формата не предусматривается.
0
Just Do It!
 Аватар для XLAT
4204 / 2662 / 654
Регистрация: 23.09.2014
Сообщений: 9,058
Записей в блоге: 3
07.12.2025, 10:38
Цитата Сообщение от Igor3D Посмотреть сообщение
Переход на "жаргон босяка" обычно говорит о неуверенности
ага, прям осень хотца быть самоуверенным криповым поцом,
типа лаки-пацан от фортуны,
осень хотца купить лотерейный билет.
чекнуть жакпот, ходить с понтом,
вальяжно так щуриться на мир - типа вот он я,
везетак, прущий с самого утра типа чистая мана в кармане пахнет,

но цыкотно, очкую, бро -
не долюбливаю я самоуверенных кретинов - не нравятся они мне - слишком много зла уверенно они делают.
0
 Аватар для Наталья8
523 / 373 / 66
Регистрация: 09.03.2016
Сообщений: 3,966
07.12.2025, 12:43
Igor3D,
Что то ни где документально не подтверждено, что вы уважаемый, эксперт по плюсам.
Igor3D,
Чё вас на плюсы то вдруг потянуло? Да ещё чужой код разбирать(обсирать)..
0
 Аватар для Наталья8
523 / 373 / 66
Регистрация: 09.03.2016
Сообщений: 3,966
07.12.2025, 12:44

Ваши темы по плюсам. (Это все...)
0
Модератор
Эксперт Java
 Аватар для alecss131
2856 / 1363 / 406
Регистрация: 11.08.2017
Сообщений: 4,351
Записей в блоге: 2
07.12.2025, 13:19
Цитата Сообщение от XLAT Посмотреть сообщение
чтобы модель можно было экспортировать под любую платформу, под любой драйвер, под любую железку...
Что за бред? Бинарь тоже спокойно экспортируется, с текстовым надо еще тратиться на парсинг строк. Про десятичные знаки уже писал, но повторюсь еще раз, тут вообще крайне не удобно. Десятичный знак зависит от локали и даже на одной ОС в пределах одной архитектуры, но с разной локалью будут проблемы, вечно не тот формат туда пишу если использую. Нумерация в индексах с единицы, тоже надо будет исправлять. Еще от ОС зависит перенос строки CRLF или LF, тоже может сломать файл. Еще числа с плавающей точкой они и бинарные не очень точные, но вот в текстовом виде их хранить еще хуже.
Так что в плане универсальности ужаснее бинарных.
Цитата Сообщение от Igor3D Посмотреть сообщение
На мой взгляд, массив здесь - нездоровая затея. Лучше потратить пару строк но видеть какие данные читаются.
Все нормально, здоровая затея, все будет видно, это же статический массив, замена обычным сишным массивам [] с константным размером, но более удобная, оно по размерам и чтении/записи ничем не отличается (то есть эквивалентно int arr[3] или std::array<int, 3> arr).
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6189 / 2891 / 1042
Регистрация: 01.06.2021
Сообщений: 10,607
07.12.2025, 13:32
Цитата Сообщение от alecss131 Посмотреть сообщение
с текстовым надо еще тратиться на парсинг строк
преимущество текстового в том, что можно редактировать в блокноте. Например, иногда я вручную отвязываю mtl от obj файла, удаляя всего одну строку. Я это делаю, когда хочется получить чистый obj без ссылки на материал. Если просто удалить mtl, то при импорте obj будут выводиться предупреждения, что связанный mtl-файл не найден. Поэтому я редактирую в текстовом редакторе сам obj. Редактировать одну строку быстрее, чем импортировать obj в 3d софт, а потом заново экспортировать.
Вообще, не всегда бинарный формат это хорошо. Например, майкрософт раньше для документов в своем офисе использовала бинарный формат DOC. Но этот формат оказался очень уязвимым, посредством него вирусы распространяли. Поэтому они перешли на современный текстовый формат DOCX - по сути, это архив с текстовыми данными.
0
Эксперт функциональных языков программированияЭксперт С++
 Аватар для Royal_X
6189 / 2891 / 1042
Регистрация: 01.06.2021
Сообщений: 10,607
07.12.2025, 13:43
Цитата Сообщение от XLAT Посмотреть сообщение
ага, прям осень хотца быть самоуверенным криповым поцом
Посмотри на этих самоуверенных фемейлов на видео. Почему они довольны? Потому что они удовлетворены результатом.

Наталья8, можешь положить видео в свою коллекцию)
Вложения
Тип файла: zip video.zip (2.29 Мб, 20 просмотров)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
07.12.2025, 13:43
Помогаю со студенческими работами здесь

Разбор строки
Здравствуйте. В stdin программы приходит строка вида domain=d.ru&amp;type=delete&amp;file=std&amp;... При...

Интерпретатор выражений с переменной(разбор и анализ строки))
Может у кого есть библиотечка по данному сабжу? В идеале надо чтобы пользователь мог вводить любую...

Консоль, разбор командной строки
#include &lt;iostream&gt; int main(int ArgumentsCount, char **Arguments) { char **p; char **l; ...

Разбор строки
Помогите разобрать вот такие строки: 2011/07/01 22:08:29 1...

Разбор сложной строки с аргументами
Здравствуйте друзья! Мне кажеться я заблудился в этой жизни(( В мою длл через пайп поступает...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru