Recent

Author Topic: GuessEncoding and CovertEncoding, with SDFDataset, on Linux  (Read 27520 times)

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #30 on: November 09, 2016, 01:18:36 pm »
Hi, guys, it seems that the latest version of the package (by GetMem) works indeed! :D
at least I hope, because it shows Win1252, while it should be WIN1250(?).
Screenshot attached.
« Last Edit: November 09, 2016, 01:22:44 pm by tatamata »

Thaddy

  • Hero Member
  • *****
  • Posts: 19474
  • Glad to be alive.
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #31 on: November 09, 2016, 01:24:20 pm »
If the sample is not big enough, this code will fail too, but 1252 covers all of 1250 below 128. The larger the sampletext, the better the result.
Yup! As does mine. Not much difference between the translations. Knowing Getmem, my version is about the same minus formatting. (and warnings!  >:D that aren't there)
Let's check some more... This code is actually really good. By Nikolaj Yakowlew, not by Getmem or me.
« Last Edit: November 09, 2016, 01:29:17 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #32 on: November 09, 2016, 09:56:14 pm »
I started to write unit with procedure for CSV file conversion to UTF8:
Code: Pascal  [Select][+][-]
  1. unit UnitUTF8Conversion;
  2. //This unit contains encoding/codepage converting routines for CSV (i.e. textual) files
  3.  
  4. {$mode objfpc}{$H+}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, Dialogs,
  10.   { FileUtil,} lazfileutils, lazutf8, LConvEncoding,
  11.   chsd_dll_intf, dynlibs;
  12.  
  13. procedure ConvertCSVFileEncodingToUTF8(pFilePathName: string);
  14. function DetermineCSVFileEncoding(pFilePathName: string): string;
  15. function MapEncoding(pCharsetInfo: string): string;
  16.  
  17. implementation
  18. type
  19.   MapCharsetInfo = record
  20.     Name: PChar;
  21.     CodePage: integer;
  22.     Language: PChar;
  23.     LazEncoding: string;
  24.     end;
  25.  
  26. const
  27.   MAP_CHARSETS: array [1..32] of MapCharsetInfo = (
  28.     // UNKNOWN_CHARSET
  29.     (
  30.     Name: 'Unknown';
  31.     CodePage: -1;
  32.     Language: 'Unknown';
  33.     LazEncoding: '';
  34.     ),
  35.     // PURE_ASCII_CHARSET
  36.     (
  37.     Name: 'ASCII';
  38.     CodePage: 0;
  39.     Language: 'ASCII';
  40.     LazEncoding: '';
  41.     ),
  42.     // UTF8_CHARSET
  43.     (
  44.     Name: 'UTF-8';
  45.     CodePage: 65001;
  46.     Language: 'Unicode';
  47.     LazEncoding: 'utf8';
  48.     ),
  49.     // UCS4_BE_CHARSET
  50.     (
  51.     Name: 'X-ISO-10646-UCS-4-3412';
  52.     CodePage: 12001;
  53.     Language: 'Unicode';
  54.     LazEncoding: '';
  55.     ),
  56.     // UTF16_BE_CHARSET
  57.     (
  58.     Name: 'UTF-16BE';
  59.     CodePage: 1201;
  60.     Language: 'Unicode';
  61.     LazEncoding: '';
  62.     ),
  63.     // UTF32_BE_CHARSET
  64.     (
  65.     Name: 'UTF-32BE';
  66.     CodePage: 12001;
  67.     Language: 'Unicode';
  68.     LazEncoding: '';
  69.     ),
  70.     // UCS4_LE_CHARSET
  71.     (
  72.     Name: 'X-ISO-10646-UCS-4-2143';
  73.     CodePage: 12000;
  74.     Language: 'Unicode';
  75.     LazEncoding: '';
  76.     ),
  77.     // UTF32_LE_CHARSET
  78.     (
  79.     Name: 'UTF-32LE';
  80.     CodePage: 12000;
  81.     Language: 'Unicode';
  82.     LazEncoding: '';
  83.     ),
  84.     // UTF16_LE_CHARSET
  85.     (
  86.     Name: 'UTF-16LE';
  87.     CodePage: 1200;
  88.     Language: 'Unicode';
  89.     LazEncoding: '';
  90.     ),
  91.     // LATIN5_BULGARIAN_CHARSET
  92.     (
  93.     Name: 'ISO-8859-5';
  94.     CodePage: 28595;
  95.     Language: 'Bulgarian';
  96.     LazEncoding: '';
  97.     ),
  98.     // WINDOWS_BULGARIAN_CHARSET
  99.     (
  100.     Name: 'windows-1251';
  101.     CodePage: 1251;
  102.     Language: 'Bulgarian';
  103.     LazEncoding: 'cp1251';
  104.     ),
  105.     // KOI8_R_CHARSET
  106.     (
  107.     Name: 'KOI8-R';
  108.     CodePage: 20866;
  109.     Language: 'russian';
  110.     LazEncoding: 'koi8';
  111.     ),
  112.     // WINDOWS_1251_CHARSET
  113.     (
  114.     Name: 'windows-1251';
  115.     CodePage: 1251;
  116.     Language: 'russian';
  117.     LazEncoding: 'cp1251';
  118.     ),
  119.     // ISO_8859_5_CHARSET
  120.     (
  121.     Name: 'ISO-8859-5';
  122.     CodePage: 28595;
  123.     Language: 'russian';
  124.     LazEncoding: '';
  125.     ),
  126.     // X_MAC_CYRILLIC_CHARSET
  127.     (
  128.     Name: 'x-mac-cyrillic';
  129.     CodePage: 10007;
  130.     Language: 'russian';
  131.     LazEncoding: '';
  132.     ),
  133.     // IBM866_CHARSET
  134.     (
  135.     Name: 'IBM866';
  136.     CodePage: 866;
  137.     Language: 'russian';
  138.     LazEncoding: '';
  139.     ),
  140.     // IBM855_CHARSET
  141.     (
  142.     Name: 'IBM855';
  143.     CodePage: 855;
  144.     Language: 'russian';
  145.     LazEncoding: '';
  146.     ),
  147.     //  ISO_8859_7_CHARSET
  148.     (
  149.     Name: 'ISO-8859-7';
  150.     CodePage: 28597;
  151.     Language: 'greek';
  152.     LazEncoding: '';
  153.     ),
  154.     // WINDOWS_1253_CHARSET
  155.     (
  156.     Name: 'windows-1253';
  157.     CodePage: 1253;
  158.     Language: 'greek';
  159.     LazEncoding: 'cp1253';
  160.     ),
  161.     // ISO_8859_8_CHARSET
  162.     (
  163.     Name: 'ISO-8859-8';
  164.     CodePage: 28598;
  165.     Language: 'hebrew';
  166.     LazEncoding: '';
  167.     ),
  168.     // WINDOWS_1255_CHARSET
  169.     (
  170.     Name: 'windows-1255';
  171.     CodePage: 1255;
  172.     Language: 'hebrew';
  173.     LazEncoding: 'cp1255';
  174.     ),
  175.     // BIG5_CHARSET
  176.     (
  177.     Name: 'Big5';
  178.     CodePage: 950;
  179.     Language: 'ch';
  180.     LazEncoding: '';
  181.     ),
  182.     // ISO_2022_CN_CHARSET
  183.     (
  184.     Name: 'ISO-2022-CN';
  185.     CodePage: 50227;
  186.     Language: 'ch';
  187.     LazEncoding: '';
  188.     ),
  189.     // ISO_2022_JP_CHARSET
  190.     (
  191.     Name: 'ISO-2022-JP';
  192.     CodePage: 50222;
  193.     Language: 'japanese';
  194.     LazEncoding: '';
  195.     ),
  196.     // ISO_2022_KR_CHARSET
  197.     (
  198.     Name: 'ISO-2022-KR';
  199.     CodePage: 50225;
  200.     Language: 'kr';
  201.     LazEncoding: '';
  202.     ),
  203.     // EUC_JP_CHARSET
  204.     (
  205.     Name: 'EUC-JP';
  206.     CodePage: 51932;
  207.     Language: 'japanese';
  208.     LazEncoding: '';
  209.     ),
  210.     // EUC_KR_CHARSET
  211.     (
  212.     Name: 'EUC-KR';
  213.     CodePage: 51949;
  214.     Language: 'kr';
  215.     LazEncoding: '';
  216.     ),
  217.     // X_EUC_TW_CHARSET
  218.     (
  219.     Name: 'x-euc-tw';
  220.     CodePage: 51936;
  221.     Language: 'ch';
  222.     LazEncoding: '';
  223.     ),
  224.     // SHIFT_JIS_CHARSET
  225.     (
  226.     Name: 'Shift_JIS';
  227.     CodePage: 932;
  228.     Language: 'japanese';
  229.     LazEncoding: '';
  230.     ),
  231.     // GB18030_CHARSET
  232.     (
  233.     Name: 'GB18030';
  234.     CodePage: 54936;
  235.     Language: 'ch';
  236.     LazEncoding: '';
  237.     ),
  238.     // HZ_GB_2312_CHARSET
  239.     (
  240.     Name: 'HZ-GB-2312';
  241.     CodePage: 52936;
  242.     Language: 'ch';
  243.     LazEncoding: '';
  244.     ),
  245.     // WINDOWS_1252_CHARSET
  246.     (
  247.     Name: 'windows-1252';
  248.     CodePage: 1252;
  249.     Language: 'eu';
  250.     LazEncoding: 'cp1252';
  251.     )
  252.   );
  253.  
  254. procedure ConvertCSVFileEncodingToUTF8(pFilePathName: string);
  255. var
  256.   About: rAboutHolder;
  257.   Info: rCharsetInfo;
  258.   Fs: TFilestream;
  259.   P: PChar;
  260.   vOriginalEncoding: string;
  261.   sl: TStringList;
  262. begin
  263.   if FileExistsUTF8(pFilePathName) then begin
  264.      try
  265.         if LibHandle = NilHandle then begin
  266.           ShowMessage ('Error! I could not load Charset Detector library! Alternative method for charset detection will be used.');
  267.           Exit;
  268.         end;
  269.         csd_GetAbout(About);
  270.         {
  271.          ShowMessage(About.About);
  272.         }
  273.  
  274.         // Backup original CSV file
  275.         sl:=TStringList.Create;
  276.         sl.LoadFromFile(pFilePathName);
  277.         sl.SaveToFile(pFilePathName+'.bcp');
  278.  
  279.         // Read CSV file
  280.         Fs := TFilestream.Create(pFilePathName, fmOpenReadWrite);
  281.         P := AllocMem(Fs.Size);
  282.         Fs.ReadBuffer(P^, Fs.Size);
  283.  
  284.         csd_Reset;
  285.         csd_HandleData(PChar(P), Length(P));
  286.         if not csd_Done() then
  287.           csd_DataEnd;
  288.         Info := csd_GetDetectedCharset();
  289.  
  290.         {
  291.          ShowMessage(Info.Name + sLineBreak +
  292.                      InttoStr(Info.CodePage) + sLineBreak +
  293.                      Info.Language);
  294.         }
  295.  
  296.         //Convert File Charset Encoding
  297.         if (Info.Name<>'') then begin
  298.            vOriginalEncoding:=MapEncoding(Info.Name);
  299.            P:=PChar(ConvertEncoding(P, vOriginalEncoding, EncodingUTF8));
  300.         end
  301.         else begin
  302.            vOriginalEncoding:=GuessEncoding(P);
  303.            P:=PChar(ConvertEncoding(P, vOriginalEncoding, EncodingUTF8));
  304.         end;
  305.  
  306.         // Save CSV File
  307.         Fs.Seek(0, soFromBeginning);
  308.         Fs.WriteBuffer(Pointer(P)^, UTF8Length(P));
  309.  
  310.         ShowMessage('The CSV file "' + pFilePathName + '" is analyzed. '
  311.             + 'Charset detected by Charset Detection Library: ' + Info.Name + ','
  312.             + 'Charset detected by GuessEncoding function: ' + GuessEncoding(P) + '.' + LineEnding
  313.             + 'The CSV file "' + pFilePathName + '" is converted to UTF8, while original CSV file is preserved as backup file: "' + pFilePathName + '.bcp".');
  314.  
  315.       finally
  316.         {
  317.          FreeMem(P); // I had to comment this, because it crashes application...Why?
  318.         }
  319.         Fs.Free;
  320.         sl.Free;
  321.      end;
  322.   end
  323.   else begin
  324.     ShowMessage('The file: ' + pFilePathName + ' does not exist!');
  325.   end;
  326. end;
  327.  
  328. function DetermineCSVFileEncoding(pFilePathName: string): string;
  329. var
  330.   About: rAboutHolder;
  331.   Info: rCharsetInfo;
  332.   Fs: TFilestream;
  333.   P: PChar;
  334.   sl: TStringList;
  335. begin
  336.   if FileExistsUTF8(pFilePathName) then begin
  337.      try
  338.         Result:='';
  339.         if LibHandle = NilHandle then begin
  340.           ShowMessage ('Error! I could not load Charset Detector library! Alternative method for charset detection will be used.');
  341.           Result:='';
  342.           Exit;
  343.         end;
  344.         csd_GetAbout(About);
  345.         {
  346.          ShowMessage(About.About);
  347.         }
  348.  
  349.         // Read CSV file
  350.         Fs := TFilestream.Create(pFilePathName, fmOpenReadWrite);
  351.         P := AllocMem(Fs.Size);
  352.         Fs.ReadBuffer(P^, Fs.Size);
  353.  
  354.         csd_Reset;
  355.         csd_HandleData(PChar(P), Length(P));
  356.         if not csd_Done() then
  357.           csd_DataEnd;
  358.         Info := csd_GetDetectedCharset();
  359.  
  360.         {
  361.          ShowMessage(Info.Name + sLineBreak +
  362.                      InttoStr(Info.CodePage) + sLineBreak +
  363.                      Info.Language);
  364.         }
  365.  
  366.         Result:=Info.Name;
  367.  
  368.         ShowMessage('The CSV file "' + pFilePathName + '" is analyzed. '
  369.             + 'Charset detected by Charset Detection Library: ' + Info.Name + ','
  370.             + 'Charset detected by GuessEncoding function: ' + GuessEncoding(P) + '.');
  371.  
  372.       finally
  373.         FreeMem(P);
  374.         Fs.Free;
  375.         sl.Free;
  376.      end;
  377.   end
  378.   else begin
  379.     ShowMessage('The file: ' + pFilePathName + ' does not exist!');
  380.   end;
  381. end;
  382.  
  383. function MapEncoding(pCharsetInfo: string): string;
  384. var i:Integer;
  385. begin
  386.   Result:='';
  387.   for  i:=Low(MAP_CHARSETS) to High(MAP_CHARSETS) do begin
  388.     if (MAP_CHARSETS[i].Name=pCharsetInfo) then begin
  389.       Result:=MAP_CHARSETS[i].LazEncoding;
  390.     end;
  391.   end;
  392. end;
  393.  
  394. end.
  395.  
  396.  
Can you help me with mapping? For most of the array elements I don't know which string to provide for LazEncoding...

Also, to confute myself, my test csv file was recognized as win1252 instead of win1250 and these are not the same - some characters are represented correctly, some not. If I change cp1252 to cp1250 in mapping with windows-1252:
Code: Pascal  [Select][+][-]
  1.     // WINDOWS_1252_CHARSET
  2.     (
  3.     Name: 'windows-1252';
  4.     CodePage: 1252;
  5.     Language: 'eu';
  6.     LazEncoding: 'cp1252';
  7.     )
  8.  
to
Code: Pascal  [Select][+][-]
  1.     // WINDOWS_1252_CHARSET
  2.     (
  3.     Name: 'windows-1252';
  4.     CodePage: 1252;
  5.     Language: 'eu';
  6.     LazEncoding: 'cp1250';
  7.     )
  8.  
then the conversion is good...
Obviosuly, the charset detection library lacks some encodings...
« Last Edit: November 10, 2016, 07:18:31 am by tatamata »

balazsszekely

  • Guest
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #33 on: November 10, 2016, 08:50:03 am »
Quote
Can you help me with mapping? For most of the array elements I don't know which string to provide for LazEncoding...
Take a look at LConvEncoding unit. A few type is already implemented. I'm afraid you have to do the others.

Quote
Obviosuly, the charset detection library lacks some encodings...
In order to use that library a lot of works needs to be done. You can't use it in production yet.


Thaddy

  • Hero Member
  • *****
  • Posts: 19474
  • Glad to be alive.
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #34 on: November 10, 2016, 09:21:16 am »
I am working on the ICU alternative, which is the standard detection library. But I also disagree to some extend that a lot of work needs to be done on this particular code.
Point me to what you want? Because this is pure Pascal, so from a purist point of view I actually like it.

BTW: 1252 vs 1250 is an issue: it should favor 1250 over 1252, but that is easy to fix.
« Last Edit: November 10, 2016, 09:25:57 am by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

balazsszekely

  • Guest
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #35 on: November 10, 2016, 09:30:57 am »
Quote
@Thaddy
Point me to what you want? Because this is pure Pascal, so from a purist point of view I actually like it.
I believe he stated many times what he would like to do: convert from any encoding to UTF8. With the current library this is not yet possible.

Thaddy

  • Hero Member
  • *****
  • Posts: 19474
  • Glad to be alive.
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #36 on: November 10, 2016, 09:33:15 am »
Correct. That's also the case with the ICU stuff. It is not a converter, but a  detector/predictor.
Any "programmer" that knows only one programming language is not a programmer

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #37 on: November 10, 2016, 12:29:18 pm »
Correct. That's also the case with the ICU stuff. It is not a converter, but a  detector/predictor.
Well, once you have accurate prediction, it should be easy to convert, right?
PLease, take a look at my naive code upwards, do you think it is correct way to proceed with mapping and converting?
The idea was to map what the chsdset detects (nsCore unit) with what is present in LConvEncoding unit and then perform conversion by using ConvertEncoding function. Apperently, this works, but the mapping is bad ( I don't know hot to map everything from LConvEncoding to everything in nsCore...

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #38 on: November 10, 2016, 12:30:02 pm »
Correct. That's also the case with the ICU stuff. It is not a converter, but a  detector/predictor.
Sorry for my ignorance, what is ICU?

Windsurfer

  • Sr. Member
  • ****
  • Posts: 368
    • Windsurfer

Thaddy

  • Hero Member
  • *****
  • Posts: 19474
  • Glad to be alive.
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #40 on: November 10, 2016, 01:29:32 pm »
No (well, yes and no) , That doesn't work. See my previous link. http://site.icu-project.org/

The information is correct about the subject, but I started from scratch. Because the link is not valid.
« Last Edit: November 10, 2016, 01:32:39 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

Thaddy

  • Hero Member
  • *****
  • Posts: 19474
  • Glad to be alive.
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #41 on: November 10, 2016, 01:39:52 pm »
Well, once you have accurate prediction, it should be easy to convert, right?
Well, no.
But I am busy... 8)
Note it also needs to be - because I want it - lightweight. Which these libraries are not.

By studying the subject I hope current prediction can be improved. But just speed-wise.
But most of the current code is already written by computer scientists, so don't hold your breath.
I may behave like a donkey running into a brick wall over and over again..... :P O:-)

Most of the time the wall wins, but I have been lucky enough to win once or twice.  8-)
« Last Edit: November 10, 2016, 01:53:43 pm by Thaddy »
Any "programmer" that knows only one programming language is not a programmer

tatamata

  • Hero Member
  • *****
  • Posts: 804
    • ZMSQL - SQL enhanced in-memory database
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #42 on: November 11, 2016, 07:57:01 am »
Quote
Next job for me: look at a possible  ICU-c58 interface. That's more or less the standard.
@Thaddy, what are your plans regarding ICU-c58 interface? When it could be ready for production?

Roland57

  • Hero Member
  • *****
  • Posts: 615
    • msegui.net
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #43 on: November 11, 2016, 01:29:44 pm »
I forget to add the zip file. Steps:

   1. Open "chsdet.lpi" from the "src" dir and build it
   2. Copy the library(chsdet.dll/libchsdet.so/libchsdet.dylib) to the demo folder
   3. Under linux/osx rename it to  "chsdet.so" respectively "chsdet.dylib" or change the source code accordingly
   4. Build and run the demo project

Please note: Under Osx you have to move the library into the bundle.

Compiled successfully the library and the demo program under Windows 10.

It isn't really important, but I observe that chsdet.dll has a size of 415 KB (against 132 KB for the file provided by the library author).

 
My projects are on Codeberg.

balazsszekely

  • Guest
Re: GuessEncoding and CovertEncoding, with SDFDataset, on Linux
« Reply #44 on: November 11, 2016, 02:36:25 pm »
@RolandC
If you switch to release mode the dll size will decrease from 415 KB to 183 KB. Still a little bit bigger then the delphi counterpart(probably compiled with an older version of delphi).

PS: Nowadays the size of the binary it's not so important. Personally I find totally irrelevant.

 

TinyPortal © 2005-2018