воскресенье, 15 октября 2023 г.

Преобразование строки в массив чисел float

Я писал уже про то как получал данные от компрессора в своем блоге и потом чуть больше на хабре. Речь сейчас идет больше за первый описываемый компрессор, где данные передаются в виде строки. Недавно мне пришлось немного менять его код и я увидел что он "несколько странный" - преобразование строки в массив строк происходит через поиск первого символа разделителя ( в моем случае ";" ) а затем сокращение строки на количество символов до этого разделителя и затем повтор по циклу. Причем в первоначальном варианте был жестко привязан размер массива на 35 элементов, что потом вылезло в проблемы, которые пришлось решать - по какой-то причине количество элементов сократилось и цикл стал выходить за диапазон индекса массива:

    string answer = req.ResponseText;
    answer = answer.Replace("&", ";");
    float[] strarr = new float[35];
    for (int i = 0; i< 35; i++)
    {
        int position = answer.IndexOf(";");
        string str = answer.Substring(0,position);
        strarr [i] = float.Parse(str, CultureInfo.InvariantCulture.NumberFormat);
        answer = answer.Substring(position+1);
    }

Для этого добавил счетчик элементов по количеству встречаемых символов ";" и чтобы не добавлять пустую строку в конце сделал еще и условие позиции этого символа:

    string answer = req.ResponseText;
    answer = answer.Replace("&", ";");
    int count = 0;
    foreach (char c in answer) if (c ==';') count++;
    float[] strarr = new float[count+1];
    int position = 0;
    int i = 0;
    do
    {
        position = answer.IndexOf(";");
        if (position>0) {
            string str = answer.Substring(0,position);
            strarr [i] = float.Parse(str, CultureInfo.InvariantCulture.NumberFormat);
            answer = answer.Substring(position+1);
            i++;
        }          
    }
    while (position>0);

Это избавило от ошибки выхода за границы массива, но не сделало код красивее и проще, и тем более оптимальнее, почему в тот раз не обратился к конструкции Split я не помню, но в этот раз решил исправить, но правда без нюансов не обошлось - последний элемент массива строк пустой, и из-за этого преобразование во float выдавало ошибку

    string answer = req.ResponseText;
    answer = answer.Replace("&", ";");
    string[] strarr = answer.Split(';');
    float[] floarr = new float[strarr.Length];
    if (strarr.Length > 1)
    {
        for (int i = 0; i < strarr.Length-1; i++)
        {
            floarr[i] = float.Parse(strarr[i], CultureInfo.InvariantCulture.NumberFormat);
        }
    }

Кстати этот код можно упростить удалив строку с Replace, а все потому что метод Split может разделять строку по нескольким разделителям, то есть нужно задать там ; и & чтобы разделить на массив. Также этот код можно упростить используя Array.ConvertAll, но я так долго разбирался с тем почему происходит ошибка даже на таком элементарном коде который выше, что решил что ну его нафиг, пусть остается так, лучше напишу просто заметку об этом и скину ссылку как еще можно преобразовать массив. Вообще было бы еще интересно сравнить какое преобразование оптимальнее, чтобы точно убедиться что лучше)), хотя оба кода работают нормально вцелом. Хотя опять же - нет никакой валидации на входе - если компрессор место числа выдаст какой-липо символ и пустоту, то в очередной раз будет ошибка и будет необходимость переписывать код...

PS не поленился и в онлайн режиме (на сайте майкрософт с описанием метода Split можно включить проверку кода) сделал компиляцию предыдущего случая и упрощенного до 3 строк кода, причем последний пустой элемент массива удаляется автоматически, используя перегрузку метода Split, о чем говорилось и в статье майкрософт:

    string answer = req.ResponseText;
    string[] strarr = answer.Split(new char[] { ';', '&' }, StringSplitOptions.RemoveEmptyEntries);
    float[] floarr = Array.ConvertAll(strarr, s => float.Parse(s, CultureInfo.InvariantCulture.NumberFormat));
Вот и очередной лайфхак, как все это дело проверять - можно проверять онлайн, а редактором для блога использовать онлайн vscode))) отличная работа)
Чтобы проверить можно сделать так :
    string answer = "95.460999;01;65.000000;99.811996&109.811996;01;75.000000";
    string[] strarr = answer.Split(new char[] { ';', '&' }, StringSplitOptions.RemoveEmptyEntries);
    float[] floarr = Array.ConvertAll(strarr, s => float.Parse(s, CultureInfo.InvariantCulture.NumberFormat));
    foreach (var sub in floarr)
    {
    Console.WriteLine($"Substring: {sub}");
    }

Комментариев нет:

Отправить комментарий