La función Length no devuelve el número de caracteres de una cadena MBCS, sino la cantidad de bytes, así que aquí presentamos la AnsiLength

Determinando la longitud real de una cadena

Copyright © 2000 Ernesto De Spirito

Help & Manual authoring tool

Introducción

La función Length nos devuelve la longitud de una cadena, pero se comporta de modo diferente según el tipo de cadena. Para las viejas cadenas cortas (ShortString) y para las cadenas largas (AnsiString), Length devuelve la cantidad de bytes que tiene una cadena, mientras que para las cadenas anchas (WideString) devuelve la cantidad de caracteres anchos (WideChar), es decir la cantidad de bytes dividido dos.

En el caso de las cadenas cortas y largas, en los idiomas occidentales un caracter ocupa un byte, mientras que por ejemplo en idiomas asiáticos algunos caracteres ocupan un byte y otros dos. Es por esta razón que existen dos versiones de casi todas las funciones de cadena, una de gran rendimiento que sólo sirve para cadenas con caracteres de un sólo byte (SBCS) y otra de menor rendimiento que sirve también para cadenas de caracteres de uno o dos bytes (DBCS) y que se usan principalmente por quienes pretenden distribuir aplicaciones internacionalmente. Así es que por ejemplo tenemos funciones como Pos, LowerCase y UpperCase por un lado y AnsiPos, AnsiLowerCase y AnsiUpperCase por otro. Curiosamente no hay una función AnsiLength que nos devuelva la cantidad de caracteres de una cadena DBCS.

AnsiLength (Borrador)

Aquí va entonces una función que devuelve la cantidad de caracteres de una cadena de dos bytes:

uses SysUtils;

function AnsiLength(const s: string): integer;
var
  i, n: integer;
begin
  Result := 0;
  n := Length(s);
  i := 1;
  while i <= n do begin
    inc(Result);
    if s[i] in LeadBytes then inc(i);
    inc(i);
  end;
end;

AnsiLength (Final)

Naturalmente, esta función no está optimizada. No vamos a meternos con lenguaje ensamblador, pero por lo menos podemos usar punteros:

uses SysUtils;

function AnsiLength(const s: string): integer;
var
  p, q: pchar;
begin
  Result := 0;
  p := PChar(s);
  q := p + Length(s);
  while p < q do begin
    inc(Result);
    if p^ in LeadBytes then
      inc(p, 2)
    else
      inc(p);
  end;
end;
JfControls Library - para Delphi y C++ Builder