Jolie entrée en matière. Salut à toi aussi !
Pas d'unicode en 2007 sous Delphi je te rappelle.
Mais je pleure aussi en voyant ta liste ; jamais entendu parler de FoldString ? Cette API est pourtant disponible depuis Windows 2000... Voici un exemple qui date de 2009 !
Papy214 avait aussi proposé une jolie variante à base de TEncoding en 2017.
Et non, il ne suffit pas de créer un tableau (à moins de d'abord normaliser les chaînes à coup de NormalizeString) puisque Ä, pour un même affichage, peut se coder #$C4 ou décomposé #$41#$308 (A + ¨).
Si: TNTUnicode
Trop d'exceptions, trop lent.Mais je pleure aussi en voyant ta liste ; jamais entendu parler de FoldString ? Cette API est pourtant disponible depuis Windows 2000... Voici un exemple qui date de 2009 !
Le tableau ne fait les minuscules, majuscules, diacritiques, sait de quelle langue est un caractère (sympa pour séparer les séquence en en langue Hiragana/Katagana/Occidental etc.. quand il n'y a aucun espace entre eux), et on sait quel type de caractère, ce qui permet de nombreuses combinaisons.
Oui, trop lent. SCASW est plus rapide que CASE... et sans tableau !Papy214 avait aussi proposé une jolie variante à base de TEncoding en 2017.
Ce sont des combinaisons spécifique rares qui peuvent se faire avant.Et non, il ne suffit pas de créer un tableau (à moins de d'abord normaliser les chaînes à coup de NormalizeString) puisque Ä, pour un même affichage, peut se coder #$C4 ou décomposé #$41#$308 (A + ¨).
Il est évident que reprendre un code basé sur Char de 2007 donc AnsiChar ne peut absolument pas être recopié dans un Delphi récent Unicode où Char est un WideChar
Idem pour la manipulation de chaine, en 2007 Length et Size étaient confondues ce qui est faux en Unicode
Sans parler de tenter de prendre de l'ASM 32Bits et le passer en ASM 64Bits
Comme ce type déclaré
Autant être le plus proche de la réalité
Code : Sélectionner tout - Visualiser dans une fenêtre à part TUnicodesChars = array[0..$FFFF] of TUnicodeChar;
ce qui simplifie la fonction
Code : Sélectionner tout - Visualiser dans une fenêtre à part TUnicodesChars = array[WideChar] of TUnicodeChar;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 function Minuscule(WCh: WideChar): WideChar; begin Result := UnicodesChars[WCh].LowCase; end;
Mais comme le fait remarquer AndNotOr, FoldString ou TEncoding, ça sera mieux que des fonctions approximatives bricolés dans son coin face à des fonctions OS éprouvés par des milliards d'utilisateurs.
EDIT :
J'ai retrouvé un code de 2004 pour D3, très similaire au proposition avec du array[Char]
Mais comme c'était pour une recherche médicale, j'avais poussé le vice à gérer ¾½¼ pour que l'utilisateur puisse trouver son article avec '1/2' en toutes lettres, évidemment les ligatures étaient aussi gérées, pour cœur et œdème pour citer les plus facile à trouver pour un informaticien comme exemple
FoldString aurait remplacé une unité de 1000 lignes.
Ah bon Par exemple ?
Quel rapport avec la suppression des accents ?
Pas vu de CASE et une chaîne n'est-ce pas un tableau de caractères ?
Ta routine à base de SCASW (et une liste incomplète) est certainement rapide pour traiter un caractère mais pour une chaîne ce sera un CALL par char ; ce sera juste le principe le plus lent de tous (inline n'est pas possible dû à l'assembleur). Un essai à partir de ce texte, (répété 10 000x sinon c'est pas mesurable) montre les résultats suivants : TEncoding = 109ms, FoldString = 1.393s et SCASW = 3.698s.
Sans surprise ta fonction a été intégrée ainsi :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 function TexteSansAccent(const aValue: string): string; begin SetLength(Result, aValue.Length); for var i := 1 to aValue.Length do Result[i] := SansAccent(aValue[i]); end;
Et avec ton tableau unicode, comment vas-tu savoir que tu es dans une zone valide sans CASE, comment traites-tu les surrogates et d'ailleurs pourquoi 65 536 puisque l'unicode peut contenir 1 114 111 entrées ?
Et donc tu vas perdre du temps à normaliser les chaînes... au cas où !
C'est vrai que l'on y pense peu que c'est de UTF-16 qui à l'instar de l'UTF-8 a aussi des tableaux d'extension pour un second élément de 16 bits
Déjà que le tableau TUnicodesChars pour 65 536 ça doit occuper 524Ko à plus de 4Mo pour l'ensemble des combinaisons actuelles (rien ne dit que d'autres extension ne peuvent pas être ajoutées)
Faut juste aller voir sur le site cité : https://learn.microsoft.com/en-us/wi...et-foldstringw
SCASW est en réponse à la première question sur l'algo de conversion accent/sans accent proposé, que j'ai décliné.Quel rapport avec la suppression des accents ?
Le tableau de caractère n'a rien a voir avec SCASW.Pas vu de CASE et une chaîne n'est-ce pas un tableau de caractères ?
On peut voir les 2 autres algo (TEncoding et FoldString ) ?Ta routine à base de SCASW (et une liste incomplète) est certainement rapide pour traiter un caractère mais pour une chaîne ce sera un CALL par char ; ce sera juste le principe le plus lent de tous (inline n'est pas possible dû à l'assembleur). Un essai à partir de ce texte, (répété 10 000x sinon c'est pas mesurable) montre les résultats suivants : TEncoding = 109ms, FoldString = 1.393s et SCASW = 3.698s.
Sans surprise ta fonction a été intégrée ainsi :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 function TexteSansAccent(const aValue: string): string; begin SetLength(Result, aValue.Length); for var i := 1 to aValue.Length do Result[i] := SansAccent(aValue[i]); end;
Oui, le nombre augmente chaque année. Il a été décidé de limiter les "caractères" unicodes à un tableau de 16 bits pour plus de rapidité.Et avec ton tableau unicode, comment vas-tu savoir que tu es dans une zone valide sans CASE, comment traites-tu les surrogates et d'ailleurs pourquoi 65 536 puisque l'unicode peut contenir 1 114 111 entrées ?
Chaque caractère, ou symbole de syllabe, a sa propre langue. On découpe les termes dans la langue souhaitée. De nombreux traducteurs dans le monde (en ligne) utilisent cette méthode depuis 2003.
Ben je vois pas grand chose à part les habituels problèmes d'allocation ou de validité.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 function NoAccent(const Source: string): string; var K: TArray<Byte>; begin K := TEncoding.Convert(TEncoding.Unicode, TEncoding.ASCII, TEncoding.Unicode.GetBytes(Source)); Result := StringOf(K); end; function RemoveDiacritics(const aValue: string): string; begin SetLength(Result, FoldString(MAP_COMPOSITE, PChar(aValue), Length(aValue), nil, 0)); FoldString(MAP_COMPOSITE, PChar(aValue), Length(aValue), PChar(Result), Length(Result)); for var i := Result.Length downto 1 do if Result[i].GetUnicodeCategory = TUnicodeCategory.ucNonSpacingMark then Delete(Result, i, 1); end; function SansAccent(WCh : WideChar): WideChar; const Char_Accents : PWideChar = 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ'; Char_Sans_Accents : PWideChar = 'AAAAAAaaaaaaOOOOOOooooooEEEEeeeeCcIIIIiiiiUUUUuuuuyNn'; asm OR AX, AX JE @@2 MOV ECX, 53 PUSH EDI MOV EDI, Char_Accents REPNE SCASW // Recherche le caractère JNE @@1 // Pas trouvé SUB EDI, Char_Accents ADD EDI, Char_Sans_Accents MOV AX, [EDI - 2] @@1: POP EDI @@2: end; function TexteSansAccent(const aValue: string): string; begin SetLength(Result, aValue.Length); for var i := 1 to aValue.Length do Result[i] := SansAccent(aValue[i]); end; procedure TForm1.FormCreate(Sender: TObject); begin const Text = TStringList.Create; Text.LoadFromFile('D:\Temp\nouveau 1.txt', TEncoding.UTF8); var Watch := TStopWatch.StartNew; for var i := 1 to 10000 do NoAccent(Text.Text); Memo1.Lines.Add(Watch.ElapsedMilliseconds.ToString); Watch := TStopWatch.StartNew; for var i := 1 to 10000 do RemoveDiacritics(Text.Text); Memo1.Lines.Add(Watch.ElapsedMilliseconds.ToString); Watch := TStopWatch.StartNew; for var i := 1 to 10000 do TexteSansAccent(Text.Text); Memo1.Lines.Add(Watch.ElapsedMilliseconds.ToString); end;
Tiens une petite modif qui multipliera la vitesse par 10. Inutile en effet de tester les caractères ASCII puisqu'ils sont déjà sans accent.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 function SansAccent(WCh : WideChar): WideChar; const Char_Accents : PWideChar = 'ÀÁÂÃÄÅàáâãäåÒÓÔÕÖØòóôõöøÈÉÊËèéêëÇçÌÍÎÏìíîïÙÚÛÜùúûüÿÑñ'; Char_Sans_Accents : PWideChar = 'AAAAAAaaaaaaOOOOOOooooooEEEEeeeeCcIIIIiiiiUUUUuuuuyNn'; asm // OR AX, AX // JE @@2 CMP AX, 128 JB @@2 MOV ECX, 53 PUSH EDI MOV EDI, Char_Accents REPNE SCASW // Recherche le caractère JNE @@1 // Pas trouvé SUB EDI, Char_Accents ADD EDI, Char_Sans_Accents MOV AX, [EDI - 2] @@1: POP EDI @@2: end;
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager