gifts2017

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

Опубликовал Сергей Смирнов (Serginio) в раздел Программирование - Практика программирования

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

Конечно можно использовать и вариант через ADO  http://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. Андрей Тарлыков (Tarlich) 25.06.15 16:37
//во всех типовых есть 

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

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


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

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

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

Давно не встречал так замечательно оформленного кода. Читается на раз-два.
Serginio, Вы если код выкладываете в публикации, хотя бы оформляйте его в читабельном виде!
8. Сергей Смирнов (Serginio) 01.07.15 10:31
(7) Это уже стиль. Приходится писать на нескольких языках. Ну и если работает, то не трожь
9. Николай ~ ~ (kuzyara) 22.08.16 15:43
10. Сергей Смирнов (Serginio) 22.08.16 16:04
(9) На вкус и цвет ... Главное результат и скорость
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа