пятница, 28 августа 2026 г.

Открытие файлов *.mwp через скопированный Step-7 Microwin

Проблема такая: Siemens заблокировал установку Step-7 Microwin и Sinamics Drive ES - Starter в одну операционную систему. 

Почему так сделано - загадка, но есть решение: 

1. Устанавливаем Microwin 

2.  Заходим в C:\Program Files (x86), находим там папку STEP 7-MicroWIN V4.0, делаем ее резервную копию (лично я скопировал ее в папку C:\Programs, в которой храню portable-приложения, в дальнейшем описании используется именно эта папка)

3. Делаем юнинсталяцию Microwin. Драйвера при этом сохранятся.

4. Устанавливаем Starter

Теперь у нас есть работающий Starter и есть квази-portable версия Microwin в папке C:\Programs\STEP 7-MicroWIN V4.0. Если запускать microwin.exe и открывать в ней проекты (*.mwp) через File->Open, то проблемы нет. Однако, при попытке традиционным способом выполнить "Открыть с помощью..." для файла *.mwp с последующим выбором microwin.exe, натыкаемся на то, что сам Microwin запускается, но файл *.mwp при этом не открывает.

Делаем так: 

1. Для начала создаем и запускаем *.bat-файл для удаления ненужных разделов:

reg delete "HKEY_CLASSES_ROOT\Applications\microwin.exe" /f
reg delete "HKEY_CLASSES_ROOT\mwp_auto_file" /f
reg delete "HKEY_CLASSES_ROOT\.mwp" /f
reg delete "HKEY_CLASSES_ROOT\MicroWinFile" /f

2. Создаем и запускаем файл с расширением *.reg с таким текстом:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\.mwp]
@="MicroWINFile"

[HKEY_CLASSES_ROOT\.mwp\ShellNew]
"FileName"="C:\\Programs\\STEP 7-MicroWIN V4.0\\bin\\template.mwp"

[HKEY_CLASSES_ROOT\MicroWinFile]
@="STEP 7-MicroWIN Project"

[HKEY_CLASSES_ROOT\MicroWinFile\DefaultIcon]
@="C:\\Programs\\STEP 7-MicroWIN V4.0\\bin\\microwin.exe,0"

[HKEY_CLASSES_ROOT\MicroWinFile\shell]

[HKEY_CLASSES_ROOT\MicroWinFile\shell\open]

[HKEY_CLASSES_ROOT\MicroWinFile\shell\open\command]
@="\"C:\\Programs\\STEP 7-MicroWIN V4.0\\bin\\microwin.exe\" %1"

[HKEY_CLASSES_ROOT\MicroWinFile\shell\print]

[HKEY_CLASSES_ROOT\MicroWinFile\shell\print\command]
@="\"C:\\Programs\\STEP 7-MicroWIN V4.0\\bin\\microwin.exe\" %1 /p" 


пятница, 21 августа 2026 г.

Excel 2003. Проблема работы с несколькими файлами

В Office 2003 (*по моему мнению - последней и полностью завершенной версии этого программного продукта, после которой новых версий уже не должно было быть) есть проблема с Excel: файлы открываются вроде бы как в отдельных окнах, но если нажать крестик закрытия окна, то Excel пытается закрыть все открытые в данный момент файлы. Чтобы закрыть отдельное окно, нужно нажимать другую кнопку с крестиком - ту, которая находится в правой части строки меню. 

 

Кнопки управления окном

Т.е. программа по умолчанию ведет себя так, как будто у нас запущена одна версия приложения excel.exe, внутри которой мы открываем xls-файлы (словно разные web-страницы в общем окне браузера). Хотя по факту это совсем не так: каждый xls-файл открылся в своем экземпляре запущенного приложения, и отдельно отображается на панели задач. Дополнительная проблема: невозможно открыть несколько файлов с одинаковыми именами, несмотря на то, что это разные файлы в разных папках.

Решение.


Находим в реестре:

HKEY_CLASSES_ROOT\Excel.Sheet.8\shell\Open\command

HKEY_CLASSES_ROOT\Excel.Sheet.12\shell\Open\command 

Открываем параметры с названием (По умолчанию) в обоих этих разделах, там видим что-то такое:

"C:\PROGRA~2\MICROS~2\OFFICE11\EXCEL.EXE" /e

добавляем "%1" в конце:

"C:\PROGRA~2\MICROS~2\OFFICE11\EXCEL.EXE" /e "%1" 

Там же в реестре в тех же разделах Open есть папки ddeexec. Удаляем их.

После перезагрузки в папке HKEY_CLASSES_ROOT\Excel.Sheet.8\shell\Open\command может появиться параметр с именем command , который надо будет удалить. Можно создать *.bat файл для быстрого удаления этого параметра (для Excel.Sheet.12 на всякий случай тоже) и поместить его в автозапуск:

reg delete "HKEY_CLASSES_ROOT\Excel.Sheet.8\shell\Open\command" /v command /f

reg delete "HKEY_CLASSES_ROOT\Excel.Sheet.12\shell\Open\command" /v command /f 

воскресенье, 16 августа 2026 г.

Контроллеры и модули S7-1200 G2

CPU

CPU 1212C G2

8 DI, 6 DQ
HSC: 8
PTO/PWM: см. ниже
Импульсные DI: I0.0 – I0.7 (100 kHz)
Модули I/O + Коммуникационные: 6

WORK MEMORY: 150 KB

CPU 1212C G2

AC/DC/RLY
Импульсные DQ: нет

 

 6ES7212-1BG50-0XB0

CPU 1212C G2

DC/DC/RLY
Импульсные DQ: нет

 

 6ES7212-1HG50-0XB0

CPU 1212C G2

DC/DC/DC
Импульсные DQ: Q0.0 – Q0.5 (100 kHz)

PTO/PWM: 8

 

 6ES7212-1AG50-0XB0

CPU 1212FC G2

DC/DC/DC

WORK MEMORY: 200 KB

 

 6ES7212-1AF50-0XB0

 

CPU 1214C G2

14 DI, 10 DQ
HSC: 8
PTO/PWM: см. ниже
Импульсные DI: I0.0 – I0.7 (100 kHz)
Модули I/O + Коммуникационные: 10

WORK MEMORY: 250 KB

CPU 1214C G2

AC/DC/RLY
Импульсные DQ: нет

 

 6ES7214-1BH50-0XB0

CPU 1214C G2

DC/DC/RLY
Импульсные DQ: нет

 

 6ES7214-1HH50-0XB0

CPU 1214C G2

DC/DC/DC
Импульсные DQ: Q0.0 – Q0.7 (100 kHz)

PTO/PWM: 8

 

 6ES7214-1AH50-0XB0

CPU 1214FC G2

DC/DC/DC

WORK MEMORY: 300 KB

 

 6ES7214-1AF50-0XB0

 

CPU 1216 Plus G2 (G2++)

DI и DQ отсутствуют

WORK MEMORY: 300 KB

CPU 1216C G2++

 Осей движения: 16

 

 6ES7216-1ML50-0XB0

 

CPU 1217 Plus G2 (G2++)

DI и DQ отсутствуют

WORK MEMORY: 600 KB

CPU 1217C G2++

 Осей движения: 32

 

 6ES7217-1MM50-0XB0

 

Тип платы

Заказной номер

Количество каналов

Макс. частота / Разрешение

SB 1231 (Аналоговый вход)

6ES7231-4HD50-0XB0

4 AI

13 бит + знак (14 бит АЦП)

SB 1232 (Аналоговый выход)

6ES7232-4HD50-0XB0

4 AQ

14 бит (U) / 13 бит (I)

SB 1233 (Комбинированная AI/AQ)

6ES7233-4HD50-0XB0

2 AI / 2 AQ

14 бит

SB 1222 (Дискретный выход)

6ES7222-5BF50-0XB0

8 DQ

100 кГц

SB 1223 (Дискретный ввод/вывод)

6ES7223-7BF50-0XB0

4 DI / 4 DQ

100 кГц

SB 1223 DC/DC (Ввод/вывод 5В)

6ES7223-7BF40-0XB0

4 DI / 4 DQ

200 кГц

 

Тип модуля

Описание

Заказной номер (MLFB)

Дискретные модули (Digital)

 

 

SM 1221

DI 16 × 24 V DC (16 дискретных входов)

6ES7221-1BH50-0XB0

SM 1222

DQ 16 × 24 V DC (16 дискретных выходов, транзистор)

6ES7222-5BH50-0XB0

SM 1222

DQ 16 × Relay (16 дискретных выходов, реле)

6ES7222-5HH50-0XB0

SM 1223

DI 8 × 24V DC / DQ 8 × Relay (8 входов / 8 выходов реле)

6ES7223-5PH50-0XB0

SM 1223

DI 8 × 24V DC / DQ 8 × 24V DC (8 входов / 8 выходов)

6ES7223-5BH50-0XB0

SM 1223

DI 16 × 24V DC / DQ 16 × Relay (16 входов / 16 выходов реле)

6ES7223-5PL50-0XB0

SM 1223

DI 16 × 24V DC / DQ 16 × 24V DC (16 входов / 16 выходов)

6ES7223-5BL50-0XB0

SM 1223

DI 16 × 24V DC / DQ 16 × 24V DC (16 входов / 16 выходов, тип "сток")

6ES7223-5BL50-1XB0

Аналоговые модули (Analog)

 

 

SM 1231

AI 8 × 14 бит (8 аналоговых входов)

6ES7231-4HF50-0XB0

SM 1232

AQ 8 × 14 бит (8 аналоговых выходов)

6ES7232-4HF50-0XB0

SM 1233

AI 4 × 14 бит / AQ 4 × 14 бит (4 входа / 4 выхода)

6ES7233-4HF50-0XB0

Специализированные модули (Special)

 

 

SM 1231 RTD

AI 4 × RTD (4 входа для термосопротивлений, напр. Pt100)

6ES7231-5PD50-0XB0

SM 1231 TC

AI 8 × TC (8 входов для термопар)

6ES7231-5QF50-0XB0

Безопасные модули (Fail-safe)

 

 

SM 1226

F-DI 4x / F-DQ 2x (4 безопасных входа / 2 безопасных выхода)

6ES7226-6ME50-0XB0

 

 


суббота, 8 августа 2026 г.

Отключить функцию Split View в Firefox

 Firefox продолжает нас радовать всякими ненужными функциями, мешающими работе браузера. Одна из них - разделенный просмотр (т.е. отображение разных страниц на одном экране). Называется Split View. Отключается так:

1. открыть страницу about:config

2. найти пункт browser.tabs.splitView.enabled

3. установить его в состояние false

среда, 29 апреля 2026 г.

ATTENTION, FAKE!

(этот пост является переводом предыдущего поста на английский язык)

Eight years ago, I posted on my blog that a Vietnamese citizen was selling a so-called "miracle program" called All PLC and HMI Crack, which had a ridiculously ugly green interface that made it instantly recognizable:


Versions 4.2 and 2.2 are actually identical

The program goes by many names: "PLC HMI Password Crack," "PLC - HMI Password Decryption," "PLC HMI Password Unlock," "Crack All PLC HMI," "PLC HMI Keyword," and so on. I initially doubted that it worked, but various users started telling me in the comments that it was not fake and could actually crack something. So, after all these years, I suddenly found this program available for free, downloaded it, and tried to crack some basic things (for example, opening a password-protected S7-200 project). And it actually worked. However, there is an important thing to understand: similar cracks have been around for a long time and are no big secret. Still, at least we have confirmation that the program is real — and that is exactly what attracts potential buyers. It seems that if the old version is real, the new ones must be too.

Then I found an entire website, unlockplcbd.com, dedicated to this scam. Look at these wonderful ad brochures that the developer is showing off:

Advertising PDF #1

Advertising PDF #2

  


 

He really tried! He clearly hired a designer, because given the program's shabby green appearance, the author could not have made such PDFs himself. However, these PDFs have some obvious flaws that alone should give the scam away. For example, if you open these two documents, you might notice one very strange detail: the description of version 5.3 claims it can crack Siemens S7-200 Smart controllers, but for some reason, version 5.7 no longer includes those controllers — though it does include the S7-300, S7-400, and even the S7-1200. Where did the S7-200 Smart go? Probably the scammer simply forgot to copy that mention when designing the new brochure. The version 5.3 brochure also mentions Koyo controllers, but they are also missing from version 5.7. These strange, illogical moments should raise immediate suspicion.
 

Now let's move on to our hero of the day. Here he is:

As you can see, the phone number is published right in the program: +8801758432841. This is done deliberately so you have no doubt that it is the author communicating with you on WhatsApp — not some other scammer. Although, in fact, the author is the scammer.

Now, the most important part: what is the scammer selling? Nothing! After receiving the money, he sends a RAR archive containing the same old program that he wrote many years ago. Here is how the scam works: he originally sold this program, but at some point, buyers leaked it online, making it freely available. Instead of losing money, the scammer turned this situation into a profit. He started creating advertising PDFs for non-existent new versions of the program. His old software — now freely available because it was leaked — became a kind of "demo version" for these fake new releases.

So now, the scammer does not need to develop anything. He simply creates fake brochures for non-existent versions, collects payments, and vanishes — leaving the victim with an old, freely available program. 

Here is his program, which you can easily find online: link 
(Mirror: link)
And here is the program this scammer sent me after payment: link 
(Mirror: link)

As you can see, there is no difference — the version he sold is 4.2, though it is actually no different from version 2.2. What is more, the scammer did not even bother to fix the "About" window, so in version 4.2, that window shows version 2.3, and the software name does not match either:

 

The versions 5.3 and 5.7 that the scammer advertises in his brochures do not exist. There are only fake screenshots on his website:

 

All his advertising brochures and pseudo-screenshots are a scam. Furthermore, for those unwilling to pay him 500,thescammeroffersa500,thescammeroffersa300 option that supposedly cracks just one controller model, for example, the Siemens S7-1200. Naturally, that is also a scam.

In addition to his fancy website, the author posts videos on YouTube and spreads false information about his program on other sites.

Don't trust scammers — save your money )).

ВНИМАНИЕ, FAKE!

8 лет назад в моем блоге было сообщение о том, что некий вьетнамский гражданин продает чудо-программу под названием All PLC and HMI Crack с идиотским салатовым интерфейсом, по которому эта прога сразу идентифицируется:

 

Версии программ 4.2 и 2.2. По факту - абсолютно идентичные


У программы много названий: "PLC HMI Password Crack", "PLC - HMI Password Descryption", "PLC HMI Password Unlock", "Crack All PLC HMI", "PLC HMI Keyword" и т.п. Я изначально выражал сомнения в работоспособности данной программы, но разные пользователи начали писать мне в комментариях, что программа не фейк и что-то взламывает. И вот спустя столько лет я вдруг случайно нахожу данную программу в бесплатном доступе, скачиваю ее и пробую взломать некоторые элементарные вещи (например, открыть запороленный проект к S7-200). И оно действительно работает. Правда, тут надо понимать один важный аспект: подобные взломы давно уже реализованы и не являются тайной. Но однако, по крайней мере появилось подтверждение, что программа настоящая. И именно это является приманкой для потенциальных покупателей! Кажется, что если старая версия настоящая, то и новые тоже. Далее нахожу целый сайт unlockplcbd.com, посвященный всей этой афере. Глядите-ка какие замечательные рекламные буклеты демонстрирует разработчик данного ПО: 

 Рекламный PDF №1

 Рекламный PDF №2

 


Да уж, расстарался! Явно нанял дизайнера, ибо учитывая убогий салатовый внешний вид ПО, нарисовать такой PDF автор точно бы не смог. Правда есть явные косяки с этими PDF, которые сами по себе уже должны выдать аферу. Например, открыв эти два документа, вы можете заметить одну очень странную деталь: в описании программы v5.3 заявлено, что она якобы может вскрывать контроллеры Siemens S7-200 Smart, но в версии 5.7 по какой-то причине эти контроллеров уже нет, но зато есть S7-300, S7-400 и даже S7-1200. Куда же подевались S7-200 Smart?.. Ну, видимо, мошенник просто забыл скопировать упоминание о нем, когда верстал новый рекламный буклет. Также в буклете на версию 5.3 упомянуты контроллеры Koyo, а в версии 5.7 их почему-то уже нет. Т.е. эти странные и нелогичные моменты сразу должны вызвать подозрения.

Теперь переходим собственно к нашему герою дня. Вот он:

 


Как видим, номер телефона опубликован прямо в программе: +8801758432841. Это сделано специально, чтобы у вас не было сомнений насчет того, действительно ли с вами в WhatsApp общается автор, а не мошенники. Хотя на самом деле сам автор и есть мошенник.

Теперь самое главное: ну а что же жулик продает? А ничего! Получив деньги, он отправляет RAR-архив, содержащий ту же самую старую программу, которую он написал много лет назад. Вот как работает мошенничество. Изначально он продавал свою программу (старую), но в какой-то момент покупатели выложили её в интернет, сделав общедоступной. Вместо того чтобы потерять деньги, вьетнамский жулик превратил эту ситуацию в прибыль. Он начал создавать рекламные PDF-файлы для несуществующих новых версий программы. Его старое ПО при этом — общедоступное, потому что оно было выложено в сеть — стало своего рода демо-версией для этих поддельных новых релизов.

Таким образом, теперь мошеннику не нужно ничего разрабатывать, достаточно лишь рисовать PDF с рекламой несуществующих программ, брать деньги и сваливать.

Вот его программа, которую вы легко найдете в интернете: ссылка 

А вот программа, которую этот жулик скинул мне после оплаты: ссылка  

Как вы можете заметить, разницы нет никакой, а версия проданной программы является 4.2, хотя на самом деле ничем не отличается от версии 2.2. Мало того, жулик даже не озаботился тем, чтобы исправить окно "О программе", поэтому в версии 4.2 это окно показывает версию 2.3, да и название ПО тоже не совпадает:

 

 

Никаких версий 5.3 и 5.7, которые жулик рекламирует в своих буклетах, не существует. Есть только фальшивые скриншоты у него на сайте:

 




Все его рекламные буклеты и псевдо-скриншоты - это обман. Мало того, для тех, кто не хочет платить ему $500, жулик предлагает вариант за $300, который будет взламывать только одну модель контроллера, например, Siemens S7-1200. Естественно, что это тоже всё обман.

Помимо красивого сайта автор выкладывает ролики на Youtube и публикует лживую информацию на других сайтах о своей программе.

Не доверяйте жуликам, экономьте деньги )). 

пятница, 9 января 2026 г.

Класс QString для C++Builder

ссылка для скачивания

 

Реализация Qt-подобного строкового класса для C++Builder

Если совсем кратко говорить, то суть в том, чтобы использовать Borland'овский стандартный класс UnicodeString через методы QString из Qt. Т.е. речь идет не о чем-то новом в плане разработки, а лишь об унификации стандартов: если уже есть опыт с QString и нет желания вникать в особенности UnicodeString, то можно использовать этот класс. Также использование классов с одинаковыми методами может быть удобно с точки зрения переносимости кода между разными средами разработки. Упрощенные реализации QChar и QStringList сделаны лишь в том контексте, что они требуются классу QString, не более того.

    QChar — упрощённый аналог Qt::QChar:

  •         Хранит один символ (wchar_t).
  •         Методы для проверки типа символа (isDigit, isLetter и т.д.).
  •         Преобразование регистра (toUpper, toLower).


    QString — основная строка:

  •         Внутреннее хранение через UnicodeString
  •         Поддерживает создание из разных источников: char*, wchar_t*, std::string, std::wstring.
  •         Реализует большинство методов Qt-строки:
  •             Поиск, разделение, замена, регистр.
  •             Подстроки (mid, left, right).
  •             Числовые преобразования (toInt, toDouble).
  •             Кодировки (UTF-8, Latin1, ISO-8859-1).
  •             Форматирование (arg, number). arg() реализована лишь частично (!)
  •             Операторы сравнения и конкатенации.


    QStringList — список строк:

  •         Наследуется от std::vector<QString>.
  •         Методы: join, contains, filter.
  •         Перегруженный operator<< для добавления строк. 

 

  1. Использует встроенные возможности C++Builder (UnicodeString, UTF8String, AnsiString).

  2. Поддерживает набор кодировок и преобразований между ними.

  3. Реализует специфичные методы Qt, такие как section, simplified, toHtmlEscaped.

  4. Учитывает особенности индексации UnicodeString (начинается с 1).

 

Модуль позволяет использовать Qt-подобный строковый API в проектах на C++Builder без подключения Qt, что полезно для миграции кода или поддержки кроссплатформенных исходников с Qt-стилем работы со строками.

 

Описание класса 

 

QString для C++Builder — строковый класс с Qt-подобным интерфейсом, построенный поверх UnicodeString. Он позволяет использовать привычные имена методов — mid(), split(), replace(), arg() и другие — в проектах C++Builder без подключения библиотеки Qt.

Идея модуля — унифицировать работу со строками. Если вы уже пользуетесь QString в Qt, часть строковой логики можно записывать в похожем стиле и в C++Builder. При этом хранение текста и взаимодействие с VCL опираются на штатные средства среды: UnicodeString, UTF8String и AnsiString.ия.

1. Состав модуля и подключение

  • qstring_nx_cb.h — классы QString и QStringList, преобразования строк и специализации std::hash для обоих классов.
  • qchar_nx_cb.h — QChar для одной кодовой единицы UTF-16 и вспомогательный QCharRef для изменения символа в строке.
  • qtnamespace_nx_cb.h — перечисления в namespace Qt и шаблон Qt::QFlags. Для строк используются, в частности, CaseSensitivity, SplitBehavior и SectionFlag.

Поместите все три файла в доступный для проекта каталог. Достаточно подключить qstring_nx_cb.h: два остальных заголовка он подключает сам. Реализация находится в заголовках, отдельного .cpp у этого модуля нет. Нужен компилятор с поддержкой используемых средств C++11, включая constexpr, noexcept и перемещение.

#include "qstring_nx_cb.h"

QString text(L"Привет, C++Builder!");
UnicodeString nativeText = text.toUnicodeString();

Эти классы объявлены в глобальном пространстве имён. Подключать их одновременно с настоящими одноимёнными классами Qt в одной единице трансляции нельзя: имена конфликтуют. Наличие GUI-перечислений в qtnamespace_nx_cb.h само по себе не добавляет виджеты или систему событий Qt.

2. Создание строк и взаимодействие с VCL

Строку можно создать из QChar, UnicodeString, const char*, const wchar_t*, std::string и std::wstring. Узкие строки const char* и std::string в этих конструкторах трактуются как UTF-8. Широкие строки в целевой Windows-среде передают текст UTF-16.

QString a("Hello");
QString b(L"Привет");
QString c = QString::fromUtf8("\xD0\xA2\xD0\xB5\xD0\xBA\xD1\x81\xD1\x82");
QString d(std::string("C++Builder"));
QString e(std::wstring(L"Широкая строка"));

UnicodeString native = L"Текст VCL";
QString f(native);
UnicodeString back = f;  // Неявное преобразование в UnicodeString

Для русскоязычных литералов в примерах используется L"…", чтобы не зависеть от кодировки узкого строкового литерала в настройках проекта. Если передавать кириллицу через обычный "…", важно, чтобы компилятор формировал именно UTF-8.

// Пример внутри обработчика формы VCL
QString userText(Edit1->Text);
QString message = QString(L"Введено: %1").arg(userText.trimmed());
Label1->Caption = message.toUnicodeString();

3. Длина, пустая строка и индексация

length() возвращает число кодовых единиц UTF-16. Индексы QString начинаются с нуля, хотя внутренний UnicodeString использует индексы с единицы. Пересчёт выполняется внутри класса.

QString s(L"Привет");
int n = s.length();       // 6
QChar first = s.at(0);    // Буква П
s[0] = QChar(L'п');      // Теперь "привет"
bool empty = s.isEmpty(); // false

s.clear();
bool isNull = s.isNull(); // true

В этой реализации isNull() совпадает с isEmpty(): отдельное состояние null-строки не сохраняется. at() при неверном индексе возвращает нулевой QChar; константный operator[] ведёт себя так же. Неконстантный operator[] проверяет границы и при неверном индексе выбрасывает std::out_of_range.

Один отображаемый знак не всегда занимает одну позицию. Например, многие эмодзи представлены суррогатной парой и дают length() == 2. at(), mid(), left(), right() и другие операции с позициями работают с кодовыми единицами UTF-16; при неосторожном разрезании можно разделить пару.

4. Поиск текста

indexOf() ищет первое вхождение, lastIndexOf() — последнее. Результат — индекс с нуля; если совпадения нет, возвращается -1. contains(), startsWith() и endsWith() отвечают на вопрос о наличии подстроки, префикса или суффикса.

QString path("config/device.ini");
int slash = path.indexOf("/");       // 6
int dot = path.lastIndexOf(".");     // 13
bool found = path.contains("device"); // true
bool ini = path.endsWith(".ini");     // true
bool cfg = path.startsWith("config"); // true
int absent = path.indexOf(".xml");    // -1

int overlaps = QString("aaaa").count("aa"); // 3: перекрытия учитываются

У методов поиска QString в этом заголовке нет параметра Qt::CaseSensitivity: поиск чувствителен к регистру. Для простого поиска без учёта регистра можно преобразовать обе строки одним и тем же способом и использовать contains(). Если нужны позиции в исходной строке, учитывайте, что преобразование регистра может менять длину текста.

QString name(L"ДАТЧИК температуры");
bool found = name.toCaseFolded().contains(
   QString(L"датчик").toCaseFolded()); // true

5. Получение подстрок и секций

left(n) и right(n) возвращают начало или конец строки, mid(position, n) — фрагмент заданной длины. Если n у mid() опущен, берётся остаток строки. Исходная строка при этом не меняется.

QString name("report_2026.csv");
QString prefix = name.left(6);    // "report"
QString ext = name.right(3);      // "csv"
QString year = name.mid(7, 4);    // "2026"
QString tail = name.mid(7);       // "2026.csv"

section() извлекает одну или несколько частей, разделённых заданной строкой. Номера частей начинаются с нуля, конечная граница включается. Отрицательные номера отсчитываются от конца.

QString key("plant/line/device/tag");
QString device = key.section("/", 2, 2); // "device"
QString group = key.section("/", 1, 2);  // "line/device"
QString tag = key.section("/", -1, -1);  // "tag"

Для section() предусмотрены флаги SectionSkipEmpty, SectionIncludeLeadingSep и SectionIncludeTrailingSep. В отличие от mid(), здесь индекс задаёт номер части, а не позицию в символах.

6. Добавление, вставка, замена и удаление

append(), prepend(), insert(), replace(), remove() и operator+= изменяют текущую строку. Они возвращают QString&, поэтому вызовы можно объединять. operator+ создаёт новый результат.

QString s("sensor");
s.prepend("[").append("]"); // "[sensor]"
s.insert(1, "new_");       // "[new_sensor]"
s.replace("new_", "");     // "[sensor]"
s.remove(0, 1);            // "sensor]"
s.chop(1);                 // "sensor"

QString title = QString("Device: ") + s;
s += "_01";                // "sensor_01"

У remove(position, n) второй аргумент означает количество удаляемых кодовых единиц. remove(text) удаляет все вхождения текста. chop(n) убирает n единиц с конца; truncate(pos) оставляет первые pos единиц. chop() и truncate() возвращают void.

QString s("Status: OK; status: OK");
s.replace("status", "State", Qt::CaseInsensitive);
// "State: OK; State: OK"

s.truncate(9);
// "State: OK"

7. Пробелы и регистр

trimmed() удаляет пробельные символы по краям. simplified() дополнительно заменяет внутренние последовательности пробельных символов одним обычным пробелом. Методы возвращают новую строку.

QString raw(L"  Датчик\t\n  давления  ");
QString a = raw.trimmed();
// "Датчик\t\n  давления"
QString b = raw.simplified();
// "Датчик давления"

QString upper = QString(L"Привет").toUpper(); // "ПРИВЕТ"
QString lower = QString(L"Привет").toLower(); // "привет"

toUpper() и toLower() используют System::Character::TCharacter. Метод toCaseFolded() содержит таблицу полного преобразования регистра Unicode и может заменять один символ несколькими. Его удобно применять при сравнении текста без учёта регистра; это не то же самое, что простое приведение к нижнему регистру.

bool same = QString(L"Straße").toCaseFolded()
      == QString("STRASSE").toCaseFolded(); // true

8. Разделение строки и QStringList

split() возвращает std::vector<QString>. По умолчанию пустые части сохраняются; Qt::SkipEmptyParts исключает их. Чтобы пользоваться join(), filter() и другими методами QStringList, явно создайте список из результата split().

QString source("red;;green;blue;");
auto all = source.split(";");
// 5 элементов: "red", "", "green", "blue", ""

QStringList colors(source.split(";", Qt::SkipEmptyParts));
QString joined = colors.join(", ");
// "red, green, blue"

QStringList содержит приватный std::vector<QString>, а не наследуется от него. Он предоставляет итераторы, size(), empty(), reserve(), push_back(), insert(), erase() и другие операции в стиле vector. Добавлять строки можно и привычным operator<<.

QStringList files;
files << "report.csv" << "notes.txt" << "backup.CSV";

QStringList csv = files.filter(".csv", Qt::CaseInsensitive);
QString list = csv.join("; "); // "report.csv; backup.CSV"
bool hasNotes = files.contains("notes.txt"); // true

for(const QString& file : csv)
{
   UnicodeString nativeName = file.toUnicodeString();
   // Здесь можно передать nativeName в VCL
}

contains() у списка проверяет наличие целой строки, а filter() выбирает строки, содержащие указанную подстроку. Оба метода принимают CaseSensitivity. Сортировка без учёта регистра, фильтрация и поиск списка используют toLower(), а не полный toCaseFolded().

QStringList names = {"beta", "alpha", "beta"};
names.removeDuplicates(); // Сохраняет первые вхождения
names.sort();
QString result = names.join(" | "); // "alpha | beta"

names.replaceInStrings("alpha", "ALPHA");
QString missing = names.value(100); // Пустая строка
std::vector<QString> copy = names.toStdVector();

value(i) возвращает пустую строку при выходе за границы. first() и last() тоже возвращают пустую строку для пустого списка. removeDuplicates() возвращает void и сравнивает строки с учётом регистра. Для обычного operator[] списка действуют правила vector: индекс нужно проверять.

9. Чтение чисел из текста

toInt(), toDouble() и toFloat() поддерживают необязательный указатель bool* ok. При неудаче возвращается ноль и ok становится false. Проверять ok необходимо, если нужно отличить ошибку от корректного числа 0. Пробелы по краям удаляются, остаток строки должен целиком соответствовать числу.

bool ok = false;
int count = QString(" 42 ").toInt(&ok); // 42, ok == true
double value = QString("12.5").toDouble(&ok); // 12.5, true
int bad = QString("42px").toInt(&ok); // 0, false
int zero = QString("0").toInt(&ok);   // 0, true

В данной реализации toInt() не имеет параметра основания системы счисления. toDouble() и toFloat() используют точку как десятичный разделитель независимо от региональных настроек; строка "12,5" не является допустимой записью. Поддерживаются специальные значения inf, +inf, -inf и nan; для них ok устанавливается в true.

10. Форматирование чисел и arg()

QString::number(int) формирует десятичное целое. Перегрузка number(double, format, precision) поддерживает фиксированную форму f/F, экспоненциальную e/E и общую g/G. Для f точность задаёт число знаков после точки, для e — после точки в мантиссе, для g — число значащих цифр. По умолчанию здесь используется f с точностью 6.

QString a = QString::number(42);             // "42"
QString b = QString::number(12.5, 'f', 2);   // "12.50"
QString c = QString::number(1250.0, 'e', 2); // "1.25e+03"
QString d = QString::number(12.5, 'g', 3);   // "12.5"

arg() принимает QString, ширину поля и QChar заполнения. Каждый вызов заменяет все маркеры с наименьшим найденным номером в диапазоне от %1 до %99. Цепочка вызовов последовательно подставляет несколько значений. Для числа с нужным форматом сначала вызывайте number().

QString message = QString(L"Канал %1: %2 В")
.arg(QString::number(3))
.arg(QString::number(12.5, 'f', 2));
// "Канал 3: 12.50 В"

QString padded = QString("ID=%1")
.arg(QString::number(7), 4, QChar(L'0'));
// "ID=0007"

QString repeated = QString("%1 + %1 = %2")
.arg("A").arg("B");
// "A + A = B"

Положительная ширина arg() выравнивает текст вправо, отрицательная — влево. Строка длиннее поля не обрезается. Числовых перегрузок arg() с основанием, форматом и точностью здесь нет. Маркеры вида %L1 распознаются, но локализованное форматирование чисел не выполняется.

Конструктор QString(double) использует FloatToStr(), поэтому зависит от региональных настроек. QString::number(double, …) формирует текст с точкой. Для файлов, протоколов и предсказуемых примеров предпочтительнее явный вызов number().

Также есть статические sprintf(), asprintf() и vsprintf(). Они используют printf-форматирование, после чего трактуют полученные байты как UTF-8. Типы аргументов должны соответствовать спецификаторам.

QString s = QString::asprintf("Channel %d", 3);
// "Channel 3"

11. Кодировки и обмен со стандартными строками

Для байтового текста важно явно знать кодировку. UTF-8, локальная кодовая страница Windows и Latin-1 — разные способы представления текста. В частности, Latin-1 не является Windows-1251.

Метод / источникЗначение
QString(const char*), QString(std::string)Входные байты UTF-8
fromUtf8(), fromStdString()Явное чтение UTF-8
toUtf8(), toStdString()Возвращают std::string с UTF-8
fromLocal8Bit(), toLocal8Bit()Обмен через AnsiString и локальную ANSI-кодовую страницу
fromLatin1(), fromIso8859_1()Чтение ISO-8859-1; второй метод — псевдоним первого
fromStdWString(), toStdWString()std::wstring; в целевой Windows-среде UTF-16
fromStdU16String(), toStdU16String()std::u16string, кодовые единицы UTF-16
fromStdU32String(), toStdU32String()std::u32string, преобразование кодовых точек
QString text(L"Привет");
std::string bytes = text.toUtf8();
QString restored = QString::fromUtf8(
   bytes.data(), static_cast<int>(bytes.size()));
bool same = text == restored; // true

const char latin1[] = {char(0xE9)};
QString accent = QString::fromLatin1(latin1, 1); // "é"

Перегрузки с параметром size позволяют передавать буфер заданной длины, в том числе с нулевыми байтами внутри. Без size байтовая строка читается до первого нулевого байта. Параметр size имеет тип int: если размер приходит из большого внешнего буфера как size_t, перед приведением проверьте его диапазон.

toUtf8() возвращает именно std::string, а не QByteArray. Поэтому указатель на байты получают через c_str() или data(). Храните сам std::string столько времени, сколько используется указатель.

std::string utf8 = text.toUtf8();
const char* bytes = utf8.c_str();
// bytes действует, пока utf8 существует и его буфер не изменён

12. QChar и изменение отдельной позиции

QChar хранит один wchar_t, то есть в целевой Windows-среде одну кодовую единицу UTF-16. Доступны isNull(), isValid(), isDigit(), isLetter(), isSpace(), isUpper(), isLower(), isLetterOrNumber(), digitValue(), toUpper(), toLower(), unicode(), unicode16() и toLatin1().

QChar letter(L'я');
bool isLetter = letter.isLetter(); // true
QChar upper = letter.toUpper();   // Я

QChar digit(L'7');
int value = digit.digitValue();    // 7
int absent = letter.digitValue();  // -1

QString s("abc");
s[1] = QChar(L'X');              // "aXc"
QChar c = s.at(1);

Есть константы QChar::Null, Space, LineFeed, CarriageReturn и Tabulation. Конструкторы из char, wchar_t и char16_t являются explicit. QChar(char) рассматривает один байт как беззнаковое значение, а не декодирует последовательность UTF-8. Для русской буквы используйте, например, QChar(L'Я').

isValid() здесь означает лишь «значение не равно нулю»: он не проверяет корректность Unicode и не исключает суррогаты. toLatin1() возвращает 0, если значение не помещается в диапазон 0…255. QCharRef служит посредником при записи через неконстантный QString::operator[]; его не следует сохранять после уничтожения исходной строки.

13. Повторение, выравнивание и HTML

QString line = QString("-=").repeated(3); // "-=-=-="
QString left = QString("A").leftJustified(4, QChar(L'.'));
// "A..."
QString right = QString("A").rightJustified(4, QChar(L'0'));
// "000A"

QString mask;
mask.fill(QChar(L'*'), 5); // "*****"

QString html = QString("<b>A & B</b>").toHtmlEscaped();
// "&lt;b&gt;A &amp; B&lt;/b&gt;"

toHtmlEscaped() экранирует &, <, >, двойную и одинарную кавычки. Метод подходит для вывода текста в HTML, но не заменяет обработку URL, JavaScript или других специальных контекстов. repeated() и методы выравнивания возвращают новую строку; fill() изменяет текущую.

14. Доступ к буферу и capacity()

constData(), константный data() и utf16() возвращают const wchar_t* на внутренний UTF-16-буфер. Неконстантный data() возвращает wchar_t* и перед этим вызывает UnicodeString::Unique(), отделяя разделяемые данные.

QString s("abc");
wchar_t* buffer = s.data();
buffer[1] = L'X'; // "aXc"; индекс буфера также с нуля

Записывайте только в существующие позиции 0…length()-1. Через указатель нельзя увеличивать длину строки или перезаписывать завершающий ноль. После изменения строки прежний указатель может стать недействительным; указатель на буфер временного объекта сохранять нельзя. Для пустой строки data() предоставляет место под нулевой терминатор, а не свободный буфер для добавления текста.

capacity() у QString возвращает текущую длину, а не реальную ёмкость выделенной памяти. Метода reserve() у QString в этом модуле нет. У QStringList методы reserve() и capacity() относятся к внутреннему vector и имеют обычный смысл для контейнера.

15. Сравнение и стандартные контейнеры

QString поддерживает ==, !=, <, <=, > и >=. Сравнение строк выполняется через UnicodeString и чувствительно к регистру. В заголовке также определены std::hash<QString> и std::hash<QStringList>, поэтому их можно использовать как ключи стандартных хеш-контейнеров.

#include <unordered_map>

std::unordered_map<QString, int> counters;
counters[QString("sensor_A")] = 10;
counters[QString("sensor_B")] = 20;
int value = counters[QString("sensor_A")]; // 10

16. Практический пример: разбор строки параметров

Небольшой пример объединяет разделение, удаление лишних пробелов, проверку числа и формирование результата. Формат входных данных здесь простой: имя;значение;единица измерения. Это не CSV-парсер с поддержкой кавычек и экранирования.

QString input(L"  Давление ; 12.5 ; бар  ");
QStringList fields(input.split(";", Qt::KeepEmptyParts));
QString result;

if(fields.size() == 3)
{
   bool ok = false;
   double value = fields[1].trimmed().toDouble(&ok);
   if(ok)
   {
      result = QString(L"%1: %2 %3")
      .arg(fields[0].trimmed())
      .arg(QString::number(value, 'f', 2))
      .arg(fields[2].trimmed());
   }
   else
   {
      result = QString(L"Ошибка: неверное число");
   }
}
else
{
   result = QString(L"Ошибка: ожидаются три поля");
}
// Для этой строки: "Давление: 12.50 бар"
// В обработчике формы можно вывести:
// Label1->Caption = result.toUnicodeString();

17. Что учитывать при переносе кода из Qt

  • Набор API ограничен. В статье перечислены методы именно этого модуля; поддержка всех возможностей Qt QString, регулярных выражений и локалей не заявляется.
  • split() → vector. Для QStringList требуется явное создание из результата.
  • Байтовые результаты → std::string. У них нет методов QByteArray.
  • Поиск QString чувствителен к регистру. Параметр CaseSensitivity есть у replace() и ряда операций QStringList, но не у indexOf() или contains() строки.
  • arg() принимает строковое значение. Поддержка числовых форматов выполняется отдельным вызовом number().
  • isNull() == isEmpty(). Различие пустой и null-строки не моделируется.
  • capacity() строки — длина. Использовать его для оценки запаса памяти нельзя.
  • Зависимость от C++Builder сохраняется. Сходный интерфейс помогает переносить строковую логику, но сама реализация использует System.hpp и RTL C++Builder.

Модуль полезен, когда хочется сохранить Qt-стиль обработки строк в проекте C++Builder и удобно передавать результат в VCL через UnicodeString. При переносе конкретного участка кода следует сверять используемые перегрузки и ожидаемое поведение с этими заголовками.