С Новым годом! Форум программистов, компьютерный форум, киберфорум
Софт: Текстовые редакторы
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/3: Рейтинг темы: голосов - 3, средняя оценка - 5.00
Модератор
Эксперт по электронике
8542 / 4394 / 1651
Регистрация: 01.02.2015
Сообщений: 13,653
Записей в блоге: 9
1

[sed] Из пакетного файла в CP1251 при помощи sed вставить в итоговый файл подстроку в UTF-8

20.05.2024, 19:17. Показов 622. Ответов 5
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Доброго дня

С помощью sed и cmd (в Windows) решаю задачу формирования файла .cvs на основе другого .cvs в кодировке UTF-8.
Почти все поля нового cvs получаются перестановкой полей исходного файла. Но одно поле должно быть задано любым другим удобным способом.

Сама задача появилась из следующей проблемы.
Имеется промышленный контроллер Овен ПР205, который требуется связать по Modbus RTU (или TCP) с панелью оператора Weintek MT8072iP.
Из ПР205 возможен экспорт переменных в cvs файл в кодировке UTF-8 следующего содержания (привожу пример с 4 переменными, в реальной жизни их у меня около 50 и более).
Кликните здесь для просмотра всего текста
Код
Имя переменной;Тип переменной;Адрес регистра;Значение по умолчанию;Комментарий;Имя параметра;Минимальное значение;Максимальное значение;Видимость;Путь к параметру;Формат отображения данных;Редактирование по сети;Архивировать значение
n_Var1;Целочисленное;16384;50;Первая целочисленная переменная;Целочисленная переменная №1;0;99;Видим;Целые;Десятичный (Dec);Разрешено;Нет
n_Var2;Целочисленное;16385;150;Вторая целочисленная переменная;Целочисленная переменная №2;100;199;Видим;Целые;Десятичный (Dec);Разрешено;Нет
r_Var3;С плавающей запятой;16386;250;Первая вещественная переменная;Вещественная переменная №1;200;299;Видим;Вещественные;Десятичный (Dec);Разрешено;Нет
r_Var4;С плавающей запятой;16388;350;Вторая вещественная переменная;Вещественная переменная №2;300;399;Видим;Вещественные;Десятичный (Dec);Разрешено;Нет


Среда разработки Easy Builder для панели Weintek позволяет и импорт и экспорт тегов в csv файл кодировки UTF-8 со следующим расположением полей описаний переменных (тегов)
Кликните здесь для просмотра всего текста
Код
n_Var1,Owen_PR205,3x,16384,"Первая целочисленная переменная",16-bit Unsigned
n_Var2,Owen_PR205,3x,16385,"Вторая целочисленная переменная",16-bit Unsigned
r_Var3,Owen_PR205,3x,16386,"Первая вещественная переменная",32-bit Float
r_Var4,Owen_PR205,3x,16388,"Вторая вещественная переменная",32-bit Float


Видно, что произведена перестановка полей и замена названий типов "Целочисленная" на "16-bit Unsigned" и т.п.
А также, добавлено поле с содержимым "Owen_PR205". Это поле содержит название устройства, которое уже описано в Easy Builder - т.е. под этим названием в проекте подразумевается конфигурация связи панели с контроллером и это название даётся произвольно при конфигурировании проекта.

Задача формирования решается скриптом cmd с вызовом sed
Windows Batch file
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
@chcp 1251>nul
 
@rem Размещение утилиты - потокового редактора sed
@set sed_exe="c:\Program Files\binutils\ssed.exe"
@rem set sed_exe="c:\Program Files\binutils\sed\bin\sed.exe"
 
@rem Название исходного файла с экспортируемыми из Owen Logic тегами
@set source="ТестовыйПроект_Сетевые, Slave.csv"
@rem Название итогового файла с тегами для Easy Builder (Weintek)
@set "target=result.csv"
@rem Название устройства, уже описанного в системных параметрах проекта Easy Builder
@rem Лучше на латинице, т.к.
@set "device_name=Owen_PR205"
 
@rem Временный файл
@set "tmp_file=temp.$$1"
@rem Регулярное выражение для выделения полей в csv экспортируемых тегов
@set "field=([^;]*)[;]"
 
@rem Названия типов данных в кодировке UTF-8
@set "Owen_Unsigned_16=\xD0\xA6\xD0\xB5\xD0\xBB\xD0\xBE\xD1\x87\xD0\xB8\xD1\x81\xD0\xBB\xD0\xB5\xD0\xBD\xD0\xBD\xD0\xBE\xD0\xB5"
@set Owen_Float_32=\xD0\xA1\x20\xD0\xBF\xD0\xBB\xD0\xB0\xD0\xB2\xD0\xB0\xD1\x8E\xD1\x89\xD0\xB5\xD0\xB9\x20\xD0\xB7\xD0\xB0\xD0\xBF\xD1\x8F\xD1\x82\xD0\xBE\xD0\xB9
@set "Weintek_Unsigned_16=16-bit Unsigned"
@set "Weintek_Float_32=32-bit Float"
 
@rem Удалить заголовок (напечатать c 2 по последнюю строку)
@%sed_exe% -n "2,$p" %source%>%tmp_file%
@rem Переставить поля
@%sed_exe% -n -r "s/%field%%field%%field%%field%%field%.*/\1\,%device_name%\,3x\,\3\,\"\5\"\,\2/p" %tmp_file%>%target%
@rem Заменить тип регистра "Целочисленная" на "16-bit Unsigned"
@rem Заменить тип регистра "С плавающей запятой" на "32-bit Float"
@%sed_exe% -r "s/%Owen_Unsigned_16%$/%Weintek_Unsigned_16%/" %target%>%tmp_file%
@%sed_exe% -r "s/%Owen_Float_32%$/%Weintek_Float_32%/" %tmp_file%>%target%
 
@del %tmp_file%
Хотелось бы в переменную device_name записывать названия в том числе и на кириллице. Но проблема в том, что в итоговый файл попадёт неразборчивая абракадабра - ведь cmd в CP1251, а файл в UTF-8.

Пробовал сохранять пакетный файл в UTF-8, но тогда sed не принимал параметром файл в этой кодировке. Пришлось остаться в CP1251...

Меня устраивает итоговый текстовый файл в кодировке Unicode без BOM, т.к. импорт в Weintek имеет некоторые особенности - потребуется дополнительное объединение нескольких файлов при помощи copy.
Но на будущее, хотел бы узнать, как оставить BOM при обработке файла.
Вложения
Тип файла: 7z test.7z (724 байт, 2 просмотров)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.05.2024, 19:17
Ответы с готовыми решениями:

Изменение файла (при помощи sed)
Добрый день! Рассматриваю общую задачу: есть файл, его надо изменить, причём проще всего это...

SED Обработка файлов утилитой SED
Есть данные формата Grup 1: Podgr1 Podgr2 Podgr1 Podgr3 Grup 2:: Podgr1 Podgr2

Sed заменить подстроку в строке
Добрый день. Начала только осваивать текстовые процессоры в linux, поэтому никак не могу справиться...

Sed: не выводится в консоль stdout в кодировке UTF-8
Здравствуйте! Имеется текст, содержащий символы Unicode. Вывожу из буфера на консоль утилитой...

Вставить текст в средину блока командой SED
Нужно вставить текст в средину блока Admins { #вот сюда нужно вставить } Если пишу...

5
6301 / 2142 / 337
Регистрация: 10.12.2013
Сообщений: 7,381
22.05.2024, 15:20 2
Лучший ответ Сообщение было отмечено ФедосеевПавел как решение

Решение

Цитата Сообщение от ФедосеевПавел Посмотреть сообщение
С помощью sed и cmd (в Windows) решаю задачу формирования файла .cvs на основе другого .cvs в кодировке UTF-8.
powershell заменяет и sed, и cmd, и проблемы UTF-8, предоставляя решение в 1(одну) короткую строку.

Добавлено через 12 минут
любопытно, а почему данная задача появилась в разделе Текстовые редакторы ?

Впрочем, задачу можно решить с помощью текстового редактора.

Не менее успешно ( пожалуй, даже более успешно ) можно решить с помощью sqlite3.exe

Итак, на выбор:
  1. powershell - 1 строка
  2. nvim - 2(?) строки ( не факт, что две )
  3. sqlite - 3 строки
  4. perl - 1 строка

решение с sqlite - самое предпочтительное нмв

Добавлено через 1 час 58 минут
PR205.CSV
Ruby
1
2
3
4
5
Имя переменной;Тип переменной;Адрес регистра;Значение по умолчанию;Комментарий;Имя параметра;Минимальное значение;Максимальное значение;Видимость;Путь к параметру;Формат отображения данных;Редактирование по сети;Архивировать значение
n_Var1;Целочисленное;16384;50;Первая целочисленная переменная;Целочисленная переменная №1;0;99;Видим;Целые;Десятичный (Dec);Разрешено;Нет
n_Var2;Целочисленное;16385;150;Вторая целочисленная переменная;Целочисленная переменная №2;100;199;Видим;Целые;Десятичный (Dec);Разрешено;Нет
r_Var3;С плавающей запятой;16386;250;Первая вещественная переменная;Вещественная переменная №1;200;299;Видим;Вещественные;Десятичный (Dec);Разрешено;Нет
r_Var4;С плавающей запятой;16388;350;Вторая вещественная переменная;Вещественная переменная №2;300;399;Видим;Вещественные;Десятичный (Dec);Разрешено;Нет
PR205.SQL
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- задание разделителя полей при импорте CSV-файла
.separator ';'
 
-- импорт из файла PR205.CSV в таблицу  PR205
.import -v PR205.CSV PR205
 
-- создание таблицы-словаря для подмены значений
create table DICT(name,alias);
 
-- заполнение словаря соотв. значениями
insert into DICT values('Первая целочисленная переменная','int16');
insert into DICT values('Вторая целочисленная переменная','int32');
insert into DICT values('Первая вещественная переменная','float');
insert into DICT values('Вторая вещественная переменная','double');
 
-- вывод результата
select "Имя переменной",'Owen_PR205',"Адрес регистра",DICT.alias from PR205,DICT where PR205.Комментарий=DICT.name;
Выполнение:
Windows Batch file
1
sqlite3 < PR205.SQL
Output:
Ruby
1
2
3
4
n_Var1;Owen_PR205;16384;int16
n_Var2;Owen_PR205;16385;int32
r_Var3;Owen_PR205;16386;float
r_Var4;Owen_PR205;16388;double
0
Модератор
Эксперт по электронике
8542 / 4394 / 1651
Регистрация: 01.02.2015
Сообщений: 13,653
Записей в блоге: 9
23.05.2024, 00:06  [ТС] 3
Спасибо.

Всегда есть дефицит времени на изучение нового.

Вероятно, для следующей задачи рассмотрю вариант с PowerShell.

Добавлено через 18 минут
А как в одну строку на PS?

Ведь даже для удобства восприятия потребовалось 3 вызова sed (регулярок) и некоторое количество конфигурационных строк - названия файлов, названия типов переменных.

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

Таким образом, смогу одним вызовом получать результирующий файл. И вызывать многократно, по мере изменения количества и именования тегов.
0
6301 / 2142 / 337
Регистрация: 10.12.2013
Сообщений: 7,381
23.05.2024, 02:26 4
Лучший ответ Сообщение было отмечено ФедосеевПавел как решение

Решение

в одну строчку да, можно, но некрасиво / неудобно править

powershell :

proc.ps1 ( кодировка должна быть UTF-8 BOM )
PowerShell
1
2
3
4
5
6
7
8
9
10
11
$dict = @{
    "Первая целочисленная переменная" = "int16"
    "Вторая целочисленная переменная" = "int32"
    "Первая вещественная переменная"  = "float"
    "Вторая вещественная переменная"  = "double"
}
 
foreach ( $o in import-Csv PR205.csv -Delimiter ';' -Encoding utf8NoBOM ) {
 
  "$( $o.'Имя переменной' );Owen_PR205;$( $o.'Адрес регистра');$( $dict[$o.Комментарий])"
}
Исполнение cmd-сессия:
Windows Batch file
1
powershell -F proc.ps1
Исполнение powershell-сессия
PowerShell
1
./proc.ps1
================================================================================ ======
Perl

proc.pl (кодировка должна быть UTF-8 )
Perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
use utf8;
 
$dict = {
    "Первая целочисленная переменная" => "int16",
    "Вторая целочисленная переменная" => "int32",
    "Первая вещественная переменная"  => "float",
    "Вторая вещественная переменная"  => "double",
};
 
open CSV, "<", "pr205.csv" or die $!;
binmode CSV, 'utf8';
binmode STDOUT, 'utf8';
 
while ( readline CSV ) {
 
    next if $. == 1;                    # skip first line ( csv header )
 
    (${"Имя переменной"}, undef, ${"Адрес регистра"}, undef, ${Комментарий}) = split ";" ;
 
    printf "%s;%s;%s;%s\n", ${"Имя переменной"}, ${"Адрес регистра"},'OWEN_PR205', $dict->{${Комментарий}};
}
Исполнение cmd или powershell сессия
PowerShell
1
perl proc.pl
================================================================================ =======

Python

proc.py
Python
1
2
3
4
5
6
7
8
9
10
11
12
import csv
sys.stdout.reconfigure(encoding='utf-8')
dic = {
    "Первая целочисленная переменная" : "int16",
    "Вторая целочисленная переменная" : "int32",
    "Первая вещественная переменная"  : "float",
    "Вторая вещественная переменная"  : "double"
    }
with open('pr205.csv', mode='r', encoding='utf-8') as csv_file:
    csv_reader = csv.DictReader(csv_file, delimiter=';')
    for line in csv_reader:
        print(f'{line["Имя переменной"]};{line["Адрес регистра"]};OWEN_PR205;{dic[line["Комментарий"]]}')
Исполнение:
PowerShell
1
python proc.py
для python utf-8 не тестировал, у меня Windows-а нет.
за perl и powershell ручаюсь, если перенаправлять в > файл
1
Модератор
Эксперт по электронике
8542 / 4394 / 1651
Регистрация: 01.02.2015
Сообщений: 13,653
Записей в блоге: 9
23.05.2024, 07:32  [ТС] 5
Здорово!!!!

Вечером вернусь с работы - попробую.
Внешне выглядит не огромной скатертью, нужно выучить синтаксис и короткими скриптами преобразовывать.
0
6301 / 2142 / 337
Регистрация: 10.12.2013
Сообщений: 7,381
23.05.2024, 13:36 6
PR205__Weintek ( кодировка UTF-8 )
Код
Первая целочисленная переменная=16-bit Unsigned
Вторая целочисленная переменная=16-bit Unsigned
Первая вещественная переменная=32-bit Float
Вторая вещественная переменная=32-bit Float
proc.ps1 ( кодировка UTF-8 с BOM для powershell.exe или любой UTF-8 для pwsh.exe )*
PowerShell
1
2
3
4
5
param( $in, $out, $table )
$dict  = convertfrom-stringdata     (get-content $table -raw -encoding utf8)
$csv   = convertfrom-csv -delim ';' (get-content $in         -encoding utf8)
$csv.foreach({ $_.'Имя переменной' , 'Owen_PR205' , $_.'Адрес регистра' , $dict[$_.Комментарий] -join ';'}) | out-file $out -encoding utf8
write-host Result in file $out
Исполнение:
PowerShell
1
.\proc.ps1 -in pr205.csv -out weintek.csv -table PR205__Weintek

* версия pwsh.exe кроссплатформенная, работает на Linux, MacOS, Windows
powershell.exe for Windows должен быть обновлен до версии 5.1. это касется Windows 7 и 8.
В версиях 10,11 и так всё хорошо.
0
23.05.2024, 13:36
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
23.05.2024, 13:36
Помогаю со студенческими работами здесь

Отредактировать файл используя sed
Доброго времени суток. Прошу помощи с командой sed. Хочу использовать её для редактирования...

Вставка текста в файл sed
Добрый день. Имеется файл, в него нужно вставить /mnt/test/farch/ в начала каждой строки. Есть...

Редактор sed обрабатывает не весь файл
Здравствуйте! Я не являюсь знатоком sed, но понемногу пользуюсь. Сейчас надо в cpp и в его...

Запись переменной в файл, используя sed
Всем привет! Мне нужно записать в определённую строку текстового файла, текущую дату. делаю вот...

Замена мусора в имени файла sed
Привет. Мне нужно в папке в имени всех файлов удалить USCORE Я делаю в скрипте так:...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru