ИзСтрокиСРазделителями в Восьмерке

25.06.15

Разработка - Механизмы платформы 1С

Очень часто приходится работать с данными клиентов которые присылают данные в разных форматах в том числе и CSV.
Это аналог семерочной функции ИзСтрокиСРазделителями

Конечно можно использовать и вариант через ADO  //infostart.ru/public/98398/

Например используя Schema.ini для Microsoft.ACE.OLEDB.12.0  http://it-proposition.blogspot.ru/2011/08/schemaini-microsoftaceoledb120.html

Но данный вариант кроссплатформенный.

Функция ИзСтрокиСРазделителями(S,Delimiter=",",QuoteChar="""") Экспорт
    перем aList;
    ExtractFields(S,aList,Delimiter,QuoteChar);
    Возврат aList
КонецФункции

Функция НайтиВПодстроке(Стр1,Поз1,ИскомыйСимвол)
    Стр=Сред(Стр1,поз1);
    поз=Найти(Стр,ИскомыйСимвол);
    Если поз=0 Тогда
        возврат СтрДлина(стр1)+1
    КонецЕсли;
    Возврат поз1+поз-1
КонецФункции

Процедура ExtractFields(S,aList,Delimiter,QuoteChar)
    FieldStart=0; ScanField=1; ScanQuoted=2; EndQuoted=3;

   //{initialize by clearing the string list, and
   // starting in FieldStart state}
   // Assert(aList <> nil, 'TDExtractFields: list is nil');
    aList= новый Массив;
    if ( (S=неопределено) или (СтрДлина(S) =0 )) Тогда
        aList.Add("");
        return;
    КонецЕсли;

    State = FieldStart;

   //  RStringBuilder SB= new RStringBuilder();
    SB="";
    StartPos=1;
    EndPos=СтрДлина(S);
    Inx=1;

   // {read through all the characters in the string}
    while (Inx <=EndPos) Цикл

       //    {get the next character}
        Ch = Сред(S,Inx,1);

       //    {switch processing on the state}
        Если State =FieldStart Тогда

            if  ( Ch = QuoteChar) Тогда
                State = ScanQuoted;
                StartPos=Inx+1;
                SB="";
                Inx=НайтиВПодстроке(S,StartPos,QuoteChar);
                продолжить;
            else
                if ( Ch = Delimiter) Тогда
                    aList.Add("");
                else
                    State = ScanField;
                    StartPos=Inx;
                    Inx=НайтиВПодстроке(S,StartPos,Delimiter);
                    продолжить
                КонецЕсли;
            КонецЕсли;
        ИначеЕсли State =ScanField Тогда
            if ( Ch = Delimiter ) Тогда
                CopyCount=Inx-StartPos;
                aList.Add(Сред(S,StartPos,CopyCount));
                State = FieldStart;
            КонецЕсли
        ИначеЕсли State = ScanQuoted Тогда

            if ( Ch = QuoteChar) Тогда
                State = EndQuoted;
                CopyCount=Inx-StartPos;

               // SB.Append(S,StartPos,CopyCount);
                SB=SB+Сред(S,StartPos,CopyCount);
            КонецЕсли;
        ИначеЕсли State = EndQuoted Тогда

            if (Ch = Delimiter) Тогда
                aList.Add(SB);
                State = FieldStart;
            ИначеЕсли (Ch = QuoteChar) Тогда
                State = ScanQuoted;
                SB=SB+QuoteChar;
                StartPos=Inx+1;
                Inx=НайтиВПодстроке(S,StartPos,QuoteChar);
                продолжить
            else
                ВызватьИсключение("Нет "+Delimiter+ "в позиции ="+Inx );
            КонецЕсли;
        КонецЕсли;
        Inx=Inx+1;
    КонецЦикла;

   //  {if we are in the ScanQUoted or GotError state at the end
   //  of the string, there was a problem with a closing quote}
    if (State = ScanQuoted) Тогда
        ВызватьИсключение("Нет закрывающей скобки от поз="+Строка(StartPos-1)+
        " до конца строки");
    КонецЕсли;

   // {if the current field is not empty, add it to the list}
    if (State = EndQuoted) Тогда
        aList.Add(SB);
    ИначеЕсли (State = ScanField) Тогда
        CopyCount=Inx-StartPos;
        aList.Add(Сред(S,StartPos,CopyCount));
    КонецЕсли
КонецПроцедуры

И пример использования

Текст=Новый ЧтениеТекста(Файл,"windows-1251");
Стр = Текст.ПрочитатьСтроку();
Пока Стр <> Неопределено Цикл
    МассивЗначений=ИзСтрокиСРазделителями(Стр,РазделительПолей,ОграничительСтрок);
КонецЦикла

Например, разбирает строку:

435,"7689900--"",,,369"

где Delimiter="," и QuoteChar=""""

 

Ссылка на формат CSV:

https://ru.wikipedia.org/wiki/CSV

 

Ну и C# вариант, с которого писался данный вариант:

http://rsdn.ru/forum/dotnet/3303143.1

ИзСтрокиСразделителями

См. также

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    7462    bayselonarrend    20    

154

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    5947    dsdred    16    

80

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    17676    YA_418728146    26    

71

Перенос данных 1C Механизмы платформы 1С Системный администратор Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    11229    dsdred    44    

130

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    23763    SeiOkami    48    

135

Механизмы платформы 1С Системный администратор Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    18835    human_new    27    

80

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    14735    YA_418728146    7    

166
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Tarlich 116 25.06.15 16:37 Сейчас в теме
//во всех типовых есть 

// Функция "расщепляет" строку на подстроки, используя заданный
//      разделитель. Разделитель может иметь любую длину.
//      Если в качестве разделителя задан пробел, рядом стоящие пробелы
//      считаются одним разделителем, а ведущие и хвостовые пробелы параметра Стр
//      игнорируются.
//      Например,
//      РазложитьСтрокуВМассивПодстрок(",один,,,два", ",") возвратит массив значений из пяти элементов,
//      три из которых - пустые строки, а
//      РазложитьСтрокуВМассивПодстрок(" один   два", " ") возвратит массив значений из двух элементов
//
//  Параметры:
//      Стр -           строка, которую необходимо разложить на подстроки.
//                      Параметр передается по значению.
//      Разделитель -   строка-разделитель, по умолчанию - запятая.
//
//  Возвращаемое значение:
//      массив значений, элементы которого - подстроки
//
Функция РазложитьСтрокуВМассивПодстрок(Знач Стр, Разделитель = ",") Экспорт
    
    МассивСтрок = Новый Массив();
    Если Разделитель = " " Тогда
        Стр = СокрЛП(Стр);
        Пока 1 = 1 Цикл
            Поз = Найти(Стр, Разделитель);
            Если Поз = 0 Тогда
                МассивСтрок.Добавить(Стр);
                Возврат МассивСтрок;
            КонецЕсли;
            МассивСтрок.Добавить(Лев(Стр, Поз - 1));
            Стр = СокрЛ(Сред(Стр, Поз));
        КонецЦикла;
    Иначе
        ДлинаРазделителя = СтрДлина(Разделитель);
        Пока 1 = 1 Цикл
            Поз = Найти(Стр, Разделитель);
            Если Поз = 0 Тогда
                Если (СокрЛП(Стр) <> "") Тогда
                    МассивСтрок.Добавить(Стр);
                КонецЕсли;
                Возврат МассивСтрок;
            КонецЕсли;
            МассивСтрок.Добавить(Лев(Стр,Поз - 1));
            Стр = Сред(Стр, Поз + ДлинаРазделителя);
        КонецЦикла;
    КонецЕсли;
    
КонецФункции 
Показать
alsen; veretennikoff; echo77; fokin; Steelvan; +5 Ответить
2. Serginio 941 25.06.15 16:46 Сейчас в теме
Это не из той оперы. Смотри формат CSV https://ru.wikipedia.org/wiki/CSV
3. Tarlich 116 25.06.15 16:54 Сейчас в теме
(2) как не из этой .? сам из CSV гружу постоянно
4. Serginio 941 25.06.15 17:01 Сейчас в теме
Если бы ты внимательно прочитал то кроме разделителя строк есть еще QuteChar

Значения, содержащие зарезервированные символы (двойная кавычка, запятая, точка с запятой, новая строка) обрамляются двойными кавычками ("); если в значении встречаются кавычки — они представляются в файле в виде двух кавычек подряд


То есть Например такая строка
435,"7689900--"",,,369"
где Delimiter="," и QuoteChar=""""

Содержит значения
435
7689900--",,,369

Разбери её своим методом
5. Serginio 941 25.06.15 17:05 Сейчас в теме
6. Serginio 941 25.06.15 17:12 Сейчас в теме
Просто обычно используют разделитель табуляцию который обычно не содержится в строках или предварительно нужно заменять.
7. premierex 204 01.07.15 10:00 Сейчас в теме
while (Inx <=EndPos) Цикл

Давно не встречал так замечательно оформленного кода. Читается на раз-два.
Serginio, Вы если код выкладываете в публикации, хотя бы оформляйте его в читабельном виде!
selig; Arxxximed; Pilokarpios; +3 Ответить
8. Serginio 941 01.07.15 10:31 Сейчас в теме
(7) Это уже стиль. Приходится писать на нескольких языках. Ну и если работает, то не трожь
9. kuzyara 2090 22.08.16 15:43 Сейчас в теме
10. Serginio 941 22.08.16 16:04 Сейчас в теме
(9) На вкус и цвет ... Главное результат и скорость
15. Arxxximed 37 13.09.22 23:10 Сейчас в теме
(10) Скорость оставляет желать лучшего минимум в два раза медленнее чем Вот это
11. Arxxximed 37 13.09.22 21:10 Сейчас в теме
(8) Какая причина писать на нескольких языках? Особенно в одной конструкции использоваться и While и Цикл? Обфускация кода?
Ну хоть для публикации можно же было к единому виду привести?
12. Arxxximed 37 13.09.22 21:12 Сейчас в теме
У меня вопрос: Зачем в функции указывать QuoteChar? По моему формат CSV TSV Имеют только один символ кавычек. или у вас возникали задачи отличные от кавычек?
13. Arxxximed 37 13.09.22 21:20 Сейчас в теме
(9) В каком плане получше? В плане читабельности? или в плане алгоритма?
По Вашей статье написал и свой вариант. CSV. Чтение многострочных полей
Пока сравниваю с текущей статьей,
14. Arxxximed 37 13.09.22 21:55 Сейчас в теме
Ужасная статья по оформлению. Как и само оформление кода.

Код вываливается ошибкой, если в поле CSV будет находиться перенос строки.

Посимвольное чтение в 1С медленное - на больших файлах думаете быстро будет работать?
16. Serginio 941 15.09.22 15:17 Сейчас в теме
(11) Этот код был переписан с Delphi потом с C#
(12) Можешь указать любой. https://stackoverflow.com/questions/60902650/how-does-the-quotechar-parameter-of-the-csv-reader-function-work
(14) Ну вообще то как понять, что это не реальный перенос строки? Тут уже сам экранируй и восстанавливай.
(15) Ну значит не совсем оптимизировал. Суть в том, что читать по символьно долго, найти работает быстрее если первый символ QuoteChar
19. Arxxximed 37 15.09.22 23:38 Сейчас в теме
(16) разве в делфи и си шарпе нету готовых и встроенных библиотек чтения CSV?
17. Serginio 941 15.09.22 15:26 Сейчас в теме
(13)
Там проблема в том, что есть лишнее копирование в НайтиВПодстроке


if ( Ch = QuoteChar) Тогда
State = ScanQuoted;
StartPos=Inx+1;
SB="";
Inx=НайтиВПодстроке(S,StartPos,QuoteChar);
продолжить;
else
if ( Ch = Delimiter) Тогда
aList.Add("");
else
State = ScanField;
StartPos=Inx;
Inx=НайтиВПодстроке(S,StartPos,Delimiter);
продолжить
КонецЕсли;
КонецЕсли;

А вот найти в подстроке
Функция НайтиВПодстроке(Стр1,Поз1,ИскомыйСимвол)
Стр=Сред(Стр1,поз1);
поз=Найти(Стр,ИскомыйСимвол);
Если поз=0 Тогда
возврат СтрДлина(стр1)+1
КонецЕсли;
Возврат поз1+поз-1
КонецФункции

На момент написания не было функции
СтрНайти(<Строка>, <ПодстрокаПоиска>, <НаправлениеПоиска>, <НачальнаяПозиция>, <НомерВхождения>)
Поэтому там лишнее копирование.
Если несложно проверь через СтрНайти
18. Arxxximed 37 15.09.22 23:37 Сейчас в теме
(17) ответил вам в своей публикации Чтение многострочных полей в CSV готов подробнее обсудить там.
20. Serginio 941 16.09.22 10:12 Сейчас в теме
(18) Я просто попросил проверить заменив НайтиВПодстроке(Стр1,Поз1,ИскомыйСимвол)
на СтрНайти(<Строка>, <ПодстрокаПоиска>, <НаправлениеПоиска>, <НачальнаяПозиция>, <НомерВхождения>)
Как это скажется на производительность.
И сравнить твой алгоритм с моим.

(19) Готовых полно сейчас, а на момент написания не было. Это вообще перевод из книги https://litresp.ru/chitat/ru/%D0%91/baknell-dzhulian-m/fundamentaljnie-algoritmi-i-strukturi-dannih-v-delphi?ysclid=l845532hl4986043525

Писал еще в 2009 http://rsdn.ru/forum/dotnet/3303143.aspx
Оставьте свое сообщение