Страницы:Кликните, чтобы указать произвольную страницуназад12348495051525354555657далее
Panda: Какой язык программирования выбрать в РФ? Java, PHP, Python, C#, Rust, C++, JavaScript (часть 2)
Hance
Member
2026/39908 ответов, #1 в рейтинге
24 года на iXBT, с февраля 2001
108 фото на iXBT.photo
Чаще пишет в "Политика" (51%)
Ватикан
Инфо Ответить
Hance Member
30 дней назад / 20 января 2025 21:08
s1b
502
чего там было?
те ссылки долго не живут почему-то
s1b
Member
1735/11751 ответов, #3 в рейтинге
2 года на iXBT, с апреля 2022
Чаще пишет в "Общий" (39%)
США, AZ
Web-страница
Инфо Ответить
s
s1b Member
30 дней назад / 20 января 2025 21:11
Hance
чего там было?

По мнению GPT, там был клон Реддита. На деле - 1 поле для ввода и кнопка "Post".
Reasonable
Member
813/7006 ответов, #7 в рейтинге
2 года на iXBT, с ноября 2022
Чаще пишет в "Общий" (22%)
Швейцария, Белокаменный
Инфо Ответить
Reasonable Member
29 дней назад / 22 января 2025 03:05
Hance
Ты интересовался работой у нас. Вот предложение на работу на один из главных сайтов с требованиями:
**** Backend разработчик

Требования:

Node.js: минимум 2 года опыта коммерческой разработки.
TypeScript/JavaScript: глубокое знание, включая современные фичи и паттерны.
Фреймворки: опыт работы с Express.js, NestJS или аналогичными решениями.
API: уверенное владение RESTful API, включая проектирование, разработку и внедрение.
Базы данных: практический опыт работы с PostgreSQL, MySQL или MongoDB, умение писать сложные SQL-запросы и оптимизировать их.
Системы очередей: опыт работы с RabbitMQ, Kafka или аналогичными инструментами.
Аутентификация/авторизация: глубокое понимание принципов JWT, OAuth и других механизмов.
Контроль версий: опыт работы с Git и понимание основных принципов.
Качество кода: умение писать чистый, тестируемый и поддерживаемый код, следуя принципам SOLID, DRY и другим паттернам проектирования.

Будет плюсом:

Опыт работы с микросервисной архитектурой
Понимание CI/CD процессов и DevOps-инструментов (Docker)
Опыт работы с WebSocket

**** Frontend разработчик

Требования:

React.js: коммерческий опыт разработки на React.js от 2 лет.
JavaScript/TypeScript: глубокое понимание основ, включая современные фичи и паттерны.
Управление состоянием: практический опыт работы с Zustand, Context API или аналогичными инструментами.
API: понимание принципов работы с RESTful API.
CSS: уверенное владение CSS/Sass или опыт работы с CSS-in-JS решениями (Styled Components, Tailwind).
Верстка: знание основ адаптивной и кросс-браузерной верстки.
Контроль версий: опыт работы с Git.
Качество кода: умение писать чистый, структурированный и поддерживаемый код.

Будет плюсом:

Next.js: Опыт разработки на Next.js или других фреймворках на базе React.
SSR/SSG: Понимание принципов SSR и SSG, опыт работы с ними.

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

Ну и за сколько $(для сравнения) в месяц народ согласен работать при таких требованиях и знаниях?
Hance
Member
2028/39922 ответов, #1 в рейтинге
24 года на iXBT, с февраля 2001
108 фото на iXBT.photo
Чаще пишет в "Политика" (51%)
Ватикан
Инфо Ответить
Hance Member
28 дней назад / 22 января 2025 06:30
Reasonable

Ну и за сколько $(для сравнения) в месяц народ согласен работать при таких требованиях и знаниях?


Я за рынком не слежу
$2000-3000 на руки, $3500 если в Москве и без удалёнки

Добавление от 22.01.2025 06:30:

Фронт чуть дешевле
Hance
Member
2039/40021 ответов, #1 в рейтинге
24 года на iXBT, с февраля 2001
108 фото на iXBT.photo
Чаще пишет в "Политика" (51%)
Ватикан
Инфо Ответить
Hance Member
15 дней назад / 04 февраля 2025 19:43
https://survey.stackoverflow.co/2024/technology#2-pr…-markup-languages
К сообщению приложены файлы:
Hance
Member
2040/40022 ответов, #1 в рейтинге
24 года на iXBT, с февраля 2001
108 фото на iXBT.photo
Чаще пишет в "Политика" (51%)
Ватикан
Инфо Ответить
Hance Member
14 дней назад / 05 февраля 2025 17:17
попробовал я релизный rustrover - уже неплохо (до этого пробовал бету - не зашло)
правда, отладчик иногда отваливался когда я просматривал в нем данные - как на фото, а иногда и наглухо
но библиотеки поставились, код запустился

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

попробовал сам парсить Excel и после написания библиотеки 500+ строк остановился - да ну нафиг

пусть зреет дальше

и когда дошел до сигнатур
fn read_styles(archive: &mut ZipArchive<BufReader<File>> ) -> Result<HashMap<String, Style>, Box<dyn std::error::Error>> {
понял, что тут перебор с типами получился

Добавление от 05.02.2025 17:17:

если интересен код
001use std::collections::HashMap;
002use std::fs::{File};
003use std::io::{BufReader, Read, Write};
004use xml::reader::{EventReader, XmlEvent};
005use zip::ZipArchive;
006  
007#[derive(Debug, Clone)]
008struct CellData {
009    id: String,
010    value: String,
011    colspan: usize,
012    rowspan: usize,
013    is_merged: bool,
014    rotation: i32,
015}
016  
017#[derive(Debug, Clone)]
018struct RowData {
019    cells: Vec<CellData>,
020}
021  
022#[derive(Debug, Clone)]
023struct TableData {
024    rows: Vec<RowData>,
025}
026  
027impl TableData {
028    fn new() -> Self {
029        TableData { rows: Vec::new() }
030    }
031  
032    fn add_row(&mut self, row: RowData) {
033        self.rows.push(row);
034    }
035}
036  
037impl CellData {
038    fn new() -> Self {
039        CellData {
040            id: String::new(),
041            value: String::new(),
042            colspan: 1,
043            rowspan: 1,
044            is_merged: false,
045            rotation: 0,
046        }
047    }
048}
049  
050// Функция для парсинга sharedStrings.xml
051fn parse_shared_strings(archive: &mut ZipArchive<BufReader<File>>) -> Result<Vec<String>, Box<dyn std::error::Error>> {
052    let mut shared_strings = Vec::new();
053    let mut shared_strings_file = archive.by_name("xl/sharedStrings.xml")?;
054    let mut shared_content = String::new();
055    shared_strings_file.read_to_string(&mut shared_content)?;
056  
057    let parser = EventReader::from_str(&shared_content);
058    let mut current_text = String::new();
059  
060    for event in parser {
061        match event? {
062            XmlEvent::StartElement { name, .. } if name.local_name == "t" => {
063                current_text.clear();
064            }
065            XmlEvent::Characters(text) => current_text.push_str(&text),
066            XmlEvent::EndElement { name } if name.local_name == "t" => {
067                shared_strings.push(current_text.clone());
068            }
069            _ => {}
070        }
071    }
072  
073    Ok(shared_strings)
074}
075  
076// Функция для парсинга mergeCells
077fn parse_merge_cells(content: &str) -> Vec<(String, String)> {
078    let mut merge_pairs = Vec::new();
079    let parser = EventReader::from_str(content);
080  
081    for event in parser {
082        match event.unwrap() {
083            XmlEvent::StartElement { name, attributes, .. } => {
084                if name.local_name == "mergeCell" {
085                    for attr in attributes {
086                        if attr.name.local_name == "ref" {
087                            let refs: Vec<&str> = attr.value.split(':').collect();
088                            if refs.len() == 2 {
089                                merge_pairs.push((refs[0].to_string(), refs[1].to_string()));
090                            }
091                        }
092                    }
093                }
094            },
095            _ => {}
096        }
097    }
098    merge_pairs
099}
100  
101// Функция для преобразования адреса ячейки в координаты
102fn cell_reference_to_coordinates(reference: &str) -> (usize, usize) {
103    let mut column = 0;
104    let mut row = 0;
105    let mut parsing_column = true;
106  
107    for c in reference.chars() {
108        if c.is_alphabetic() && parsing_column {
109            column = column * 26 + (c.to_ascii_uppercase() as usize - 'A' as usize + 1);
110        } else {
111            parsing_column = false;
112            if c.is_numeric() {
113                row = row * 10 + (c as usize - '0' as usize);
114            }
115        }
116    }
117  
118    (row, column)
119}
120  
121  
122#[derive(Debug, Clone)]
123struct Style {
124    rotation: Option<i32>, // Для хранения поворота текста
125}
126  
127  
128fn parse_styles(styles_content: &str) -> HashMap<String, Style> {
129    let mut styles_map = HashMap::new();
130    let parser = EventReader::from_str(styles_content);
131    let mut in_cell_xfs = false;
132    let mut current_index = 0;
133    let mut current_style = Style {
134        rotation: None,
135    };
136    let mut in_alignment = false; // Флаг для отслеживания подэлемента <alignment>
137  
138    for event in parser {
139        if let Ok(event) = event {
140            match event {
141                XmlEvent::StartElement { name, attributes, .. } => {
142                    match name.local_name.as_str() {
143                        "cellXfs" => in_cell_xfs = true,
144                        "xf" if in_cell_xfs => {
145                            // Сброс текущего стиля перед чтением нового
146                            current_style = Style {
147                                rotation: None,
148                            };
149  
150                            for attr in attributes {
151                                match attr.name.local_name.as_str() {
152                                    "rotation" => {
153                                        //println!("Found rotation: {}", attr.value);
154                                        if let Ok(rotation) = attr.value.parse::<i32>() {
155                                            current_style.rotation = Some(rotation);
156                                        } else {
157                                            //println!("Failed to parse rotation value: {}", attr.value);
158                                        }
159                                    }
160                                    _ => {}
161                                }
162                            }
163                        }
164                        "alignment" => {
165                            in_alignment = true;
166                            // Ищем атрибут textRotation
167                            for attr in attributes {
168                                println!("some: {}", attr.value);
169                                if attr.name.local_name.as_str() == "textRotation" {
170                                    //println!("Found alignment textRotation: {}", attr.value);
171                                    if let Ok(rotation) = attr.value.parse::<i32>() {
172                                        current_style.rotation = Some(rotation);
173                                    } else {
174                                      //  println!("Failed to parse alignment textRotation value: {}", attr.value);
175                                    }
176                                }
177                            }
178                        }
179                        _ => {}
180                    }
181                }
182                XmlEvent::EndElement { name } => {
183                    if name.local_name == "alignment" {
184                        in_alignment = false;
185                    }
186                    if name.local_name == "cellXfs" {
187                        in_cell_xfs = false;
188                        // Сохраняем стиль в мапу
189                        styles_map.insert(current_index.to_string(), current_style.clone());
190                        current_index += 1;
191                    }
192                }
193                _ => {}
194            }
195        }
196    }
197  
198    styles_map
199}
200  
201fn read_sheet_content(archive: &mut ZipArchive<BufReader<File>>) -> Result<String, Box<dyn std::error::Error>> {
202    let mut sheet_content = String::new();
203    let mut sheet_file = archive.by_name("xl/worksheets/sheet1.xml")?;
204    sheet_file.read_to_string(&mut sheet_content)?;
205    Ok(sheet_content)
206}
207  
208fn read_styles(archive: &mut ZipArchive<BufReader<File>>) -> Result<HashMap<String, Style>, Box<dyn std::error::Error>> {
209    let mut styles_map = HashMap::new();
210    if let Ok(mut styles_file) = archive.by_name("xl/styles.xml") {
211        let mut styles_content = String::new();
212        styles_file.read_to_string(&mut styles_content)?;
213        styles_map = parse_styles(&styles_content);
214    }
215    Ok(styles_map)
216}
217  
218fn process_merged_cells(merge_pairs: &[ (String, String) ], merge_map: &mut HashMap<String, (usize, usize)>) {
219    for (start_ref, end_ref) in merge_pairs {
220        let (start_row, start_col) = cell_reference_to_coordinates(start_ref);
221        let (end_row, end_col) = cell_reference_to_coordinates(end_ref);
222  
223        let rowspan = end_row - start_row + 1;
224        let colspan = end_col - start_col + 1;
225  
226        merge_map.insert(start_ref.clone(), (colspan, rowspan));
227  
228        // Добавляем информацию о том, какие ячейки входят в объединение
229        for row in start_row..=end_row {
230            for col in start_col..=end_col {
231                if row != start_row || col != start_col {
232                    let cell_ref = format!(
233                        "{}{}",
234                        (col as u8 + b'A' - 1) as char,
235                        row
236                    );
237                    merge_map.insert(cell_ref, (0, 0)); // Маркируем как часть объединенной ячейки
238                }
239            }
240        }
241    }
242}
243  
244fn parse_xml_events(
245    sheet_content: &str,
246    shared_strings: &[String],
247    merge_map: &HashMap<String, (usize, usize)>,
248    styles_map: &HashMap<String, Style>  // Используем новый стиль с поворотом
249) -> Result<(Vec<RowData>, Vec<String>), Box<dyn std::error::Error>> {
250    let parser = EventReader::from_str(sheet_content);
251    let mut in_row = false;
252    let mut in_cell = false;
253    let mut current_row = Vec::new();
254    let mut current_cell = CellData::new();
255  
256    let mut current_value = String::new();
257    let mut current_type = String::new();
258    let mut rows = Vec::new();
259    let mut merged_cells = Vec::new();
260  
261    for event in parser {
262        match event? {
263            XmlEvent::StartElement { name, attributes, .. } => match name.local_name.as_str() {
264                "row" => {
265                    in_row = true;
266                    current_row.clear();
267                }
268                "c" => {
269                    in_cell = true;
270                    current_cell = CellData::new();
271                    current_value.clear();
272                    current_type.clear();
273  
274                    let mut style_index = None;
275  
276                    for attr in attributes {
277                        match attr.name.local_name.as_str() {
278                            "r" => {
279                                current_cell.id = attr.value.clone();
280                                if let Some(&(colspan, rowspan)) = merge_map.get(&current_cell.id) {
281                                    if colspan == 0 && rowspan == 0 {
282                                        current_cell.is_merged = true;
283                                    } else {
284                                        current_cell.colspan = colspan;
285                                        current_cell.rowspan = rowspan;
286                                    }
287                                }
288                            }
289                            "t" => current_type = attr.value.clone(),
290                            "s" => { // Применяем стиль
291                                style_index = Some(attr.value.clone());
292                            }
293                            _ => {}
294                        }
295                    }
296  
297                    // Применяем поворот из стиля, если он есть
298                    if let Some(style_id) = style_index {
299                        if let Some(style) = styles_map.get(&style_id) {
300                            if let Some(rotation) = style.rotation {
301                                current_cell.rotation = rotation;
302                            }
303                        }
304                    }
305                }
306                _ => {}
307            },
308            XmlEvent::Characters(text) => {
309                if in_cell {
310                    current_value = match current_type.as_str() {
311                        "s" => {
312                            if let Ok(index) = text.parse::<usize>() {
313                                shared_strings.get(index)
314                                    .map(|s| s.clone())
315                                    .unwrap_or_else(|| text.clone())
316                            } else {
317                                text.clone()
318                            }
319                        }
320                        _ => text.clone(),
321                    };
322                }
323            }
324            XmlEvent::EndElement { name } => match name.local_name.as_str() {
325                "row" => {
326                    in_row = false;
327                    rows.push(RowData { cells: current_row.clone() });
328                }
329                "c" => {
330                    in_cell = false;
331                    current_cell.value = current_value.clone();
332                    current_row.push(current_cell.clone());
333                }
334                _ => {}
335            },
336            _ => {}
337        }
338    }
339  
340    Ok((rows, merged_cells))
341}
342  
343fn parse_worksheet(
344    archive: &mut ZipArchive<BufReader<File>>,
345    shared_strings: &[String]
346) -> Result<(Vec<RowData>, Vec<String>), Box<dyn std::error::Error>> {
347    // Чтение основного содержимого
348    let sheet_content = read_sheet_content(archive)?;
349  
350    // Чтение стилей
351    let styles_map = read_styles(archive)?;
352    //let styles = read_styles(archive)?;
353    // Получаем объединенные ячейки
354    let merge_pairs = parse_merge_cells(&sheet_content);
355    let mut merge_map = HashMap::new();
356    process_merged_cells(&merge_pairs, &mut merge_map);
357  
358    // Парсим XML-содержимое, передавая styles_map
359    let (rows, merged_cells) = parse_xml_events(&sheet_content, shared_strings, &merge_map, &styles_map)?;
360  
361    Ok((rows, merged_cells))
362}
363  
364// Обработка объединенных ячеек (функция)
365fn process_merge_cells(merge_pairs: &Vec<(String, String)>, merge_map: &mut HashMap<String, (usize, usize)>) {
366    for (start_ref, end_ref) in merge_pairs {
367        let (start_row, start_col) = cell_reference_to_coordinates(start_ref);
368        let (end_row, end_col) = cell_reference_to_coordinates(end_ref);
369  
370        let rowspan = end_row - start_row + 1;
371        let colspan = end_col - start_col + 1;
372  
373        merge_map.insert(start_ref.clone(), (colspan, rowspan));
374  
375        // Добавляем информацию о том, какие ячейки входят в объединение
376        for row in start_row..=end_row {
377            for col in start_col..=end_col {
378                if row != start_row || col != start_col {
379                    let cell_ref = format!(
380                        "{}{}",
381                        (col as u8 + b'A' - 1) as char,
382                        row
383                    );
384                    merge_map.insert(cell_ref, (0, 0)); // Маркируем как часть объединенной ячейки
385                }
386            }
387        }
388    }
389}
390/*
391fn main() {
392    // Пример вызова функции с отладкой
393    let styles_content = r#"
394        <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
395            <cellXfs count="2">
396                <xf numFmtId="0" fontId="0" fillId="0" borderId="2" xfId="0" applyBorder="1" applyAlignment="1">
397                    <alignment horizontal="center" textRotation="90"/>
398                </xf>
399                <xf numFmtId="0" fontId="0" fillId="0" borderId="3" xfId="0" applyBorder="1" applyAlignment="1">
400                    <alignment horizontal="center" textRotation="90"/>
401                </xf>
402            </cellXfs>
403        </styleSheet>
404    "#;
405  
406    let styles = parse_styles(styles_content);
407  
408    // Печать полученных стилей
409    for (index, style) in styles {
410        println!("Style {}: {:?}", index, style);
411    }
412}
413*/
414  
415fn main() -> Result<(), Box<dyn std::error::Error>> {
416    let file = File::open("test.xlsx")?;
417    let reader = BufReader::new(file);
418    let mut archive = ZipArchive::new(reader)?;
419  
420    // Сначала получаем shared strings
421    let shared_strings = parse_shared_strings(&mut archive)?;
422  
423    // Передаем shared strings в parse_worksheet
424    let (rows, merged_cells) = parse_worksheet(&mut archive, &shared_strings)?;
425  
426    let mut table = TableData::new();
427    for row in rows {
428        table.add_row(row);
429    }
430  
431    // Записываем результат в файл
432    let mut output_file = File::create("output.txt")?;
433    for row in &table.rows {
434        for cell in &row.cells {
435            writeln!(output_file, "Cell ID: {}, Value: {}, Colspan: {}, Rowspan: {}, Is Merged: {}, Rotation: {}",
436                     cell.id, cell.value, cell.colspan, cell.rowspan, cell.is_merged, cell.rotation)?;
437        }
438        writeln!(output_file, "-------------------------")?;
439    }
440  
441    println!("Data has been written to output.txt");
442  
443    Ok(())
444}
К сообщению приложены файлы:
Ваш ответ:

Нет значка Нет значка Вот тут! Лампочка Восклицание Вопрос Класс! Улыбка Злость Огорчение Поговорим? Краснею Подмигивание Ругаю ОдобряюBIUdelSxsupxsuboffsp spoilerqurlimgvideo• list1. list1 codeprecenter-hr-rusQWE→ЙЦУ
файлыочистить
Ваше имя: Авторизуйтесь Предпросмотр В полную форму
вставить выделенную цитату в окно ответа
Если Вы считаете это сообщение ценным для дискуссии (не обязательно с ним соглашаться), Вы можете поблагодарить его автора, а также перечислить ему на счет некоторую сумму со своего баланса (при отзыве благодарности перечисленная сумма не будет вам возвращена).
Также вы можете оценить сообщение как неудачное.
В течение суток можно 20 раз оценить сообщения разных участников (купите Premium-аккаунт, либо оплачивайте оценки сверх лимита).
Если Вы считаете это сообщение ценным для дискуссии (не обязательно с ним соглашаться), Вы можете поблагодарить его автора, а также перечислить ему на счет некоторую сумму со своего баланса (при отзыве благодарности перечисленная сумма не будет вам возвращена).
Также вы можете оценить сообщение как неудачное.
В течение суток можно 20 раз оценить сообщения разных участников (купите Premium-аккаунт, либо оплачивайте оценки сверх лимита).
Страницы:Кликните, чтобы указать произвольную страницуназад12348495051525354555657далее
Последние обсуждения в Конференции
19:40Украина после Евромайдана. Взгляд из России. Вход для лиц с русофобскими взглядами закрыт Политика
19:39Фан клуб Ольги, которая Olga Kinda High Флуд
19:38Не совсем старые ( до 2016 г.) компьютеры и комплектующие: обсуждение работы, использования и прочее. Тех. поддержка
19:37Выбор системной платы/платформы AM5 Сист. платы
19:37Выбор бюджетного "цифрового" (китайского) усилителя Стерео
19:37Выбор Телевизора ДК TV
19:37Выбор кухонной вытяжки (всех видов) Бытовая техника
19:36Выбор 32-43" UHD монитора Мониторы
19:35Апрель. Хрустики повыползали на дороги. Осторожно! Мотоциклы. Мототема. Авто
19:35Кто-то хочет в СССР? История
19:35Надежность хранения информации Накопители
19:353D-флудилка Видеосистема
19:35Дружба! Семья
19:34Астероиды на благо Общий
19:33Сделка века. Qualcomm собирается купить Intel Процессоры
19:33Отзывы о PrivalSystems (аналог skype) Интернет
19:30Проблемы образования и выбора профессии в условиях стремительно развивающихся ии-технологий ИИ
19:29Мир Танков (World of Tanks) - обсуждение free MMO игры Игры
19:29Ноутбук. HDD в optibay шахте для DVD-привода. Высокие прерывания ACPI Ноутбуки
19:26AVITO - развод продавцов Рынок
19:30У Apple больше не будет дешевых iPhone? Представлен iPhone 16e: одна камера, большой вырез экрана и 128 ГБ памяти — за 600 долларов
18:58«Первый случай, когда ракета вылетела из одной страны, полетела в космос и приземлилась в другой стране». Новый пуск ракеты SpaceX Falcon 9 оказался историческим, о чем сообщил Илон Маск
18:31Новый Nissan Altima — всего 2,9 млн рублей. Японский седан продается в России по цене Lada Aura
18:03В России подешевели новые Mazda CX-5 — теперь от 2,7 млн рублей
17:57Командировочный «Авиасейлс» начал работать в Белоруссии
17:52Это Geely Atlas 2025: популярный кроссовер стал больше и получил новый дизайн
16:52Телескоп «Джеймс Уэбб» зафиксировал необычную активность сверхмассивной чёрной дыры Стрелец A* в центре Млечного Пути
16:34D-Wave и Staque разработали квантовое приложение для оптимизации движения агророботов
16:32Санкции? Нет, не слышали. В Россию привезли Volvo XC60 2025 прямиком из Швеции
16:26Представлена «Нива Тайга». Объявлена цена