PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » Вопросы по PureBasic » XML, ASCII и кириллица


XML, ASCII и кириллица

Сообщений 1 страница 26 из 26

1

Подскажите, пожалуйста.

Если файл xml в кодировке windows-1251, то при использовании библиотеки XML текст
на русском языке считывается в нечитаемом виде (ломается кириллица).
Есть ли какая-то возможность вернуть такой строке правильную кодировку?
Или придется отказаться в этом случае от такого удобного инструмента?
Извлекать необходимые строки по-другому в тысячах таких файлов не хотелось бы...

С уважением, Andruk

0

2

А GetXMLEncoding(#XML) используется? Я не пробовал, но гипотетически кодировка указывается в файле, значит она как то используется при чтении, а если нет, то программист должен получить её и применить при чтении. Кстати где пример использования, в чем ошибку выявлять?

0

3

Ну вот для примера.
Текст файла dada.xml:

<?xml version="1.0" encoding="windows-1251"?>
<maina>
<vira>
    <latin>Balalaika</latin>
    <russo>Балалайка</russo>
</vira>
</maina>

(Сохраните файл в кодировке windows-1251)

И код для проверки:

Код:
If LoadXML(0, "dada.xml", #PB_Ascii)
  If XMLStatus(0) = #PB_XML_Success
    *Dict = XMLNodeFromPath(MainXMLNode(0), "vira/russo")
    s$ = GetXMLNodeText(*Dict)
    Debug s$
  Else
    Debug XMLError(0)
  EndIf
Else
  Debug "Фигвам!"
EndIf

Отредактировано Andruk (27.01.2025 16:27:48)

0

4

Прочитайте данные файла через ReadFile() / ReadData() и перекодируйте строку из ascii в юникод.

Код:
If ReadFile(0, "dada.xml")
  Dim Buff.a(Lof(0))
  ReadData(0, @Buff(), ArraySize(Buff()))
  CloseFile(0)
  Xml.s = PeekS(@Buff(), ArraySize(Buff()), #PB_Ascii)
  
  If ParseXML(0, Xml)
    If XMLStatus(0) = #PB_XML_Success
      *Dict = XMLNodeFromPath(MainXMLNode(0), "vira/russo")
      Debug GetXMLNodeText(*Dict)
    Else
      Debug XMLError(0)
    EndIf
  Else
    Debug "Фигвам!"
  EndIf
  
Else
  Debug "Не удалось прочитать файл!"
EndIf

0

5

О да!
Так работает!
Спасибо огромное!

Было бы неплохо добавить такое решение в справку.
Сам бы я не догадался (ну или лет через пять).

Еще раз спасибо!

Отредактировано Andruk (27.01.2025 18:22:34)

0

6

Ещё так можно

Код:
Procedure ToCP1251(*s.Unicode)
    Protected i
    Protected *ptr.Unicode

    While *s\u
        If *s\u > 127 And *s\u < 256
            *ptr = ?CP1251 + (*s\u - 128) * 2
            *s\u = *ptr\u
        EndIf
        *s + SizeOf(Unicode)
    Wend
EndProcedure

; Здесь вы можете сделать таблицу для символов своего языка и получить содержание на своём языке вместо cp1252.
DataSection
    CP1251:
    Data.u 1026, 1027, 8218, 1107, 8222, 8230, 8224, 8225, 8364, 8240, 1033
    Data.u 8249, 1034, 1036, 1035, 1039, 1106, 8216, 8217, 8220, 8221, 8226
    Data.u 8211, 8212, 152, 8482, 1113, 8250, 1114, 1116, 1115, 1119, 160
    Data.u 1038, 1118, 1032, 164, 1168, 166, 167, 1025, 169, 1028, 171
    Data.u 172, 173, 174, 1031, 176, 177, 1030, 1110, 1169, 181, 182
    Data.u 183, 1105, 8470, 1108, 187, 1112, 1029, 1109, 1111, 1040, 1041
    Data.u 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052
    Data.u 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063
    Data.u 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074
    Data.u 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085
    Data.u 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096
    Data.u 1097, 1098, 1099, 1100, 1101, 1102, 1103
EndDataSection


If LoadXML(0, "dada.xml", #PB_Ascii)
  If XMLStatus(0) = #PB_XML_Success
    *Dict = XMLNodeFromPath(MainXMLNode(0), "vira/russo")
    s$ = GetXMLNodeText(*Dict)
    ToCP1251(@s$)
    Debug s$
  Else
    Debug XMLError(0)
  EndIf
Else
  Debug "Фигвам!"
EndIf

0

7

Спасибо! Пригодится.
Но пока предложенное Петром выглядит предпочтительнее.
А там посмотрим, как будет лучше...

0

8

Andruk
Я использую это в Linux, где нет 1251 от слова совсем, даже при использовании #PB_Ascii при чтении файла. Для Windows, кончено же лучше нативный способ.

Загуглил строку "xml encoding какие бывают" выдало что поддерживаются только две кодировки UTF-8 и UTF-16, а значит нельзя туда совать "windows-1251" как в html.

Отредактировано AZJIO (28.01.2025 00:35:16)

0

9

MSXML имеет встроенную поддержку следующих кодировок:

Код:
UTF-8
UTF-16
UCS-2
UCS-4
ISO-10646-UCS-2
UNICODE-1-1-UTF-8
UNICODE-2-0-UTF-16
UNICODE-2-0-UTF-8
It also recognizes (internally using the WideCharToMultibyte API function for mappings) the following encodings:
US-ASCII
ISO-8859-1
ISO-8859-2
ISO-8859-3
ISO-8859-4
ISO-8859-5
ISO-8859-6
ISO-8859-7
ISO-8859-8
ISO-8859-9
WINDOWS-1250
WINDOWS-1251
WINDOWS-1252
WINDOWS-1253
WINDOWS-1254
WINDOWS-1255
WINDOWS-1256
WINDOWS-1257
WINDOWS-1258

А если файлы создавались достаточно давно, то такая кодировка, увы, не редкость....
Ну и в том давнем мире размер файла имел большее значение.

Дело в том, что это Expat поддерживает только 4 кодировки:

UTF-8
UTF-16
ISO-8859-1
US-ASCII

Отредактировано Andruk (28.01.2025 03:01:09)

0

10

Может, определить кодировку?
https://g0blinish.ucoz.ru/pb2/utf8det.zip

0

11

Спасибо, но моя проблема была не в определении кодировки, а в необходимости ее изменения
для того, чтобы парсер не коверкал кириллицу.

0

12

Пётр
Привет, мне просто интересно почему именно так ты написал

Код:
  Dim Buff.a(Lof(0))
  ReadData(0, @Buff(), ArraySize(Buff()))
  CloseFile(0)
  Xml.s = PeekS(@Buff(), ArraySize(Buff()), #PB_Ascii)

а не например так?

Код:
  *buf=AllocateMemory(Lof(0))
  ReadData(0, *buf, MemorySize(*buf))
  CloseFile(0)
  Xml.s = PeekS(*buf, MemorySize(*buf), #PB_Ascii)
  FreeMemory(*buf)

0

13

Lin написал(а):

а не например так?

Можно и так.

0

14

Andruk
Полный вариант с выделением памяти. Сделал сразу после поста Петра, но не выкладывал. Массив безопаснее тем что не надо городить кучу условий, чтобы выскочить из процедуры не освободив память (перед каждым return), а массив очищается автоматически как локальный в процедуре, но тратит память на указатели, ага несколько байт.

Код:
EnableExplicit

Define length, bytes, XML$, *mem, *Dict
#File = 0
#XML = 0
If ReadFile(#File, "C:\folder\1.xml")
	length = Lof(#File)
	If length
    *mem = AllocateMemory(length)
    If *mem
    	bytes = ReadData(#File, *mem, length)
    	If bytes
        XML$ = PeekS(*mem, bytes, #PB_Ascii)
        If ParseXML(#XML, XML$)
        	If XMLStatus(#XML) = #PB_XML_Success
            *Dict = XMLNodeFromPath(MainXMLNode(#XML), "vira/russo")
            Debug GetXMLNodeText(*Dict)
        	Else
            Debug XMLError(#XML)
        	EndIf
        	FreeXML(#XML)
        Else
        	Debug "Точно XML?"
        EndIf
    	EndIf
    	FreeMemory(*mem)
    EndIf
	EndIf
	CloseFile(#File)
Else
	Debug "Не удалось прочитать файл!"
EndIf
egons написал(а):

Может, определить кодировку?

Я использую это, но в своём урезанном виде, и выкладывал исходники урезанного в некоторых своих программах, там просто лишние функции убраны, чтобы исполняемый файл был меньше.

Отредактировано AZJIO (29.01.2025 06:48:00)

0

15

Мне думается лучше заменить Debug "Точно XML?" на Debug "Ошибка памяти!"  8-)
В случае не XML-файла ParseXML все равно сработает, а XMLStatus выдаст ошибку syntax error
А вообще, какова вероятность получить ошибку ParseXML в данном коде?

Отредактировано Andruk (29.01.2025 15:10:16)

0

16

AZJIO написал(а):

Я использую это, но в своём урезанном виде, и выкладывал исходники урезанного в некоторых своих программах, там просто лишние функции убраны, чтобы исполняемый файл был меньше.

Для кодировок вещь полезная. Только UTF-8 не всегда попадается с BOM.

0

17

egons написал(а):

Только UTF-8 не всегда попадается с BOM

Надеюсь понимаешь, что ссылку, которую я дал решает эту проблему? А то выглядит как будто нет...

Andruk написал(а):

"Ошибка памяти!"

Это из справки? даже пустая строка не даёт ошибки Debug ParseXML(0, "")
Наверно нужен XML в 1 Гб, чтобы не удалось выделить память.

Andruk написал(а):

В случае не XML-файла ParseXML все равно сработает, а XMLStatus выдаст ошибку syntax error

ну да, в справке же это написано, а мы читатели.

Отредактировано AZJIO (29.01.2025 18:58:12)

0

18

AZJIO написал(а):

Надеюсь понимаешь, что ссылку, которую я дал решает эту проблему? А то выглядит как будто нет...

"Надежды юношей питают"(с)

0

19

egons написал(а):

"Надежды юношей питают"(с)

То есть я не должен надеяться что ты понимаешь?

0

20

AZJIO написал(а):

Это из справки? даже пустая строка не даёт ошибки Debug ParseXML(0, "")
Наверно нужен XML в 1 Гб, чтобы не удалось выделить память.

ну да, в справке же это написано, а мы читатели.

Извените, AZJIO, если вас как-то задел мой комментарий.
У меня нет опыта в программировании. Лет эдак 20 назад я пробывал что-то делть
на PureBasic и вот теперь на старости лет вдруг решил вернутся к нему.
Потому и нахожусь собственно на стадии изучения справки.
Так-что мои комментарии вполне себе могут выглядеть глуповато...

0

21

И все-таки по теме.
Может быть я ошибаюсь, но мне кажется, что после предыдущих условий
XML$ не может быть меньше чем length и больше чем *mem.
И поэтому ParseXML не может выдать ошибку. Или это не так?

А-а. Все понял - парсеру ведь тоже потребуется память, а ее может не хватить (теоретически).
Извиняюсь за несообразительность!

Отредактировано Andruk (30.01.2025 01:07:22)

0

22

Andruk написал(а):

И поэтому ParseXML не может выдать ошибку.

В справке написано

Эта функция возвращает 0 только в случае ошибок с памятью.

То есть если не получится выделить память.

+1

23

Один вопрос. Только не ругайтесь.
Если я делаю для себя узконаправленную утилиту и точно знаю, что не будут обрабатываться
файлы нулевого размера и размер одного файла не больше 30 Мб, то можно ли обойтись
примерно такой конструкцией?

Код:
If ReadFile(0, "dada.xml")
  sz = Lof(0)
  *buf = AllocateMemory(sz, #PB_Memory_NoClear)
  ReadData(0, *buf, sz)
  CloseFile(0)
  Xml.s = PeekS(*buf, sz, #PB_Ascii)
  FreeMemory(*buf)
  ParseXML(0, Xml)
  Xml = ""
  If XMLStatus(0) = #PB_XML_Success
    *Dict = XMLNodeFromPath(MainXMLNode(0), "vira/russo")
    Debug GetXMLNodeText(*Dict)
    ; ...
  Else
    Debug XMLError(0)
  EndIf
  FreeXML(0)
Else
  Debug "Не удалось прочитать файл!"
EndIf

Я имею ввиду излишние (в таком случае) проверки на ошибки.

Отредактировано Andruk (30.01.2025 05:16:27)

0

24

Проверки лишними обычно не бывают. При определенных обстоятельствах "лишняя" проверка может защитить от падения программу и от выдачи неправильного результата.

0

25

Лишние проверки избавят от определённого типа ошибок, которые кажутся почти невозможны. В теории пользователь может просто убить программу если она повисла. Худший вариант если прога испортит другие данные в памяти или на диске. Не смотря на то что код кажется проще и понятней, на самом деле он менее устойчивый. Не зря автор закладывает возвращение ошибок, зная что каждая функция может не выполнится. К примеру повреждение файла, вероятность 1 на миллион, вероятно поэтому ReadData() имеет возврат длины прочитанного. В MFT указан размер, но нет ссылок на все сектора файла на жёстком диске. Также использование указателя *Dict без проверки более вероятный сбой. Только вчера на оф.форуме выложенный код выдал у меня сбой из-за отсутствия проверки указателя.

+1

26

Спасибо большое!
Придется предохраняться...

Отредактировано Andruk (30.01.2025 22:40:23)

0


Вы здесь » PureBasic - форум » Вопросы по PureBasic » XML, ASCII и кириллица