- JavaScript: Strings son inmutables, codificación UTF-16
- Zig: Strings típicamente []const u8 (UTF-8), memoria explícita
- Implicación: Necesitaremos manejar conversiones Unicode y gestión de memoria
- ✅ ALTA: Implementación directa en Zig
⚠️ MEDIA: Requiere trabajo adicional (Unicode, regex, locale)- ❌ BAJA: Muy complejo o no aplicable en Zig
- 🗑️ DEPRECATED: No implementar (obsoleto en JS)
Viabilidad: ALTA
- Crear string desde valores Unicode
- Zig tiene buen soporte para code points
- Consideración: JS usa UTF-16, Zig UTF-8
- Plan: Convertir code points a UTF-8
Viabilidad: ALTA
- Similar a fromCharCode pero con code points completos
- Zig maneja code points Unicode naturalmente
- Plan: Usar std.unicode para conversión
Viabilidad: MEDIA
- Funciona con template literals (concepto JS)
- Consideración: Zig no tiene template literals
- Plan: Podría implementarse como función que procesa strings sin escapes
Viabilidad: ALTA
- Consideración CRÍTICA: En JS es cantidad de UTF-16 code units
- En Zig necesitamos decidir:
byteLength: Bytes totales (más eficiente)codePointLength: Code points Unicode (más compatible con JS)
- Plan: Implementar ambas variantes, documentar diferencia
Viabilidad: BAJA (no aplicable)
- Concepto específico de OOP de JavaScript
- En Zig usaríamos funciones init() directamente
Viabilidad: ALTA
- Acceso con índices negativos
- Plan: Implementar con índices relativos al final
- Considerar si trabajamos con bytes o code points
Viabilidad: ALTA
- Retorna carácter en índice específico
- Plan: Retornar slice de un code point
- Decidir: ¿retornar []const u8 o copiar a nuevo buffer?
Viabilidad: ALTA
- Retorna UTF-16 code unit
- Plan: En Zig retornar el code point Unicode (u21)
- Documentar que retornamos code point, no UTF-16 unit
Viabilidad: ALTA
- Retorna code point Unicode completo
- Plan: Usar std.unicode.utf8Decode
- Esta es la versión más natural en Zig
Viabilidad: ALTA
- Buscar substring, retornar índice
- Plan: Implementar búsqueda simple, luego optimizar con algoritmos como KMP o Boyer-Moore
- Decidir: índice en bytes o code points
Viabilidad: ALTA
- Búsqueda desde el final
- Plan: Similar a indexOf pero iterando desde atrás
Viabilidad: ALTA
- Verificar si contiene substring
- Plan: Wrapper sobre indexOf() != -1
- Muy directo
Viabilidad: ALTA
- Verificar prefijo
- Plan: Comparación simple de slice inicial
- std.mem.startsWith podría ayudar
Viabilidad: ALTA
- Verificar sufijo
- Plan: Comparación de slice final
- std.mem.endsWith
Viabilidad: MEDIA-BAJA
- Requiere motor de regex
- Opciones:
- Integrar biblioteca regex externa
- Implementar subset simple de regex
- Marcar como "not implemented" inicialmente
- Decisión: Fase 2, requiere investigación
Viabilidad: MEDIA-BAJA
- Como match() pero retorna iterador de todos los matches
- Mismos problemas que match()
- Plan: Fase 2
Viabilidad: MEDIA-BAJA
- Búsqueda con regex
- Misma dependencia de regex que match()
- Plan: Fase 2
Viabilidad: ALTA
- Concatenar strings
- Plan: Allocar nuevo buffer, copiar contenidos
- Necesita allocator explícito
- API:
concat(allocator, ...strings) ![]u8
Viabilidad: ALTA
- Extraer substring
- Plan: Retornar slice o copiar según parámetro
- Manejar índices negativos como JS
- Muy natural en Zig
Viabilidad: ALTA
- Similar a slice con comportamiento diferente para índices
- Plan: Implementar lógica específica de substring
- Swap de índices si start > end
Viabilidad: N/A - DEPRECATED
- No implementar, está deprecado en JS
- Usar slice() o substring()
Viabilidad: MEDIA
- Separar string en array
- Consideraciones:
- Sin regex: ALTA viabilidad (usar delimitador string)
- Con regex: MEDIA-BAJA viabilidad
- Plan Fase 1: Implementar con delimitador string simple
- Plan Fase 2: Agregar soporte regex
Viabilidad: MEDIA
- Reemplazar primera ocurrencia
- Sin regex: ALTA - búsqueda simple y reemplazo
- Con regex: MEDIA-BAJA
- Plan Fase 1: Solo strings literales
- Necesita allocator para nuevo string
Viabilidad: MEDIA
- Reemplazar todas las ocurrencias
- Similar a replace()
- Plan Fase 1: Versión con strings literales
- Más útil que replace() sin regex
Viabilidad: ALTA
- Repetir string N veces
- Plan: Allocar buffer de size * count, copiar en loop
- Optimización: usar memcpy en chunks
Viabilidad: MEDIA
- Conversión a minúsculas
- Problema: Conversión Unicode correcta es compleja
- ASCII: ALTA viabilidad
- Unicode completo: Requiere tablas de mapeo Unicode
- Plan Fase 1: ASCII simple
- Plan Fase 2: Unicode completo con std.unicode
Viabilidad: MEDIA
- Conversión a mayúsculas
- Mismos problemas que toLowerCase()
- Plan: Igual que toLowerCase()
Viabilidad: BAJA
- Requiere información de locale (idioma/región)
- Reglas complejas (ej: 'i' turca)
- Plan: Fase 3 o no implementar
- Marcar como "not implemented"
Viabilidad: BAJA
- Mismos problemas que toLocaleLowerCase()
- Plan: Fase 3 o no implementar
Viabilidad: ALTA
- Agregar padding al inicio
- Plan: Calcular padding necesario, allocar buffer, copiar
- Manejar strings de padding multi-carácter
Viabilidad: ALTA
- Agregar padding al final
- Similar a padStart()
Viabilidad: ALTA
- Remover whitespace de ambos lados
- Plan: Identificar índices de primer/último no-whitespace
- Definir whitespace según Unicode o ASCII
Viabilidad: ALTA
- Remover whitespace del inicio
- Plan: Encontrar primer no-whitespace, retornar slice
Viabilidad: ALTA
- Remover whitespace del final
- Plan: Encontrar último no-whitespace, retornar slice
Viabilidad: MEDIA-BAJA
- Comparación sensible a locale
- Requiere:
- Datos de collation Unicode (CLDR)
- Lógica compleja de sorting
- Plan:
- Fase 1: Comparación simple por code points
- Fase 2: Integrar biblioteca ICU o similar
- No prioritario
Viabilidad: MEDIA
- Normalización Unicode (NFC, NFD, NFKC, NFKD)
- Consideraciones:
- Zig tiene std.unicode pero limitado
- Requiere tablas de normalización Unicode
- Plan:
- Investigar si std.unicode.norm existe
- Si no, implementar o usar biblioteca externa
- Útil para comparaciones correctas
Viabilidad: ALTA (redundante)
- En JS convierte String object a primitivo
- En Zig: ya es un slice, no necesario
- Plan: No implementar o simplemente retornar self
Viabilidad: ALTA (redundante)
- Similar a toString()
- Plan: No implementar
Viabilidad: MEDIA
- Verifica que no haya lone surrogates (UTF-16)
- En Zig con UTF-8:
- Verificar que sea UTF-8 válido
- Plan: Usar std.unicode.utf8ValidateSlice
- Útil para validación
Viabilidad: MEDIA
- Reemplaza lone surrogates con U+FFFD
- En Zig:
- Reemplazar secuencias UTF-8 inválidas con �
- Plan: Iterar, validar, reemplazar inválidos
- Necesita allocator
Viabilidad: ALTA
- Iterador por code points
- Plan: En Zig crear struct Iterator
pub const Iterator = struct {
string: []const u8,
index: usize,
pub fn next(self: *Iterator) ?[]const u8 { ... }
};- Muy idiomático en Zig
Viabilidad: N/A - DEPRECATED
- Todos deprecated en JS moderno
- Plan: NO IMPLEMENTAR
- Sin valor práctico
- Usar DOM APIs en su lugar
Métodos esenciales y de alta viabilidad
- ✅ length (con variantes byte/codepoint)
- ✅ fromCharCode()
- ✅ fromCodePoint()
- ✅ at()
- ✅ charAt()
- ✅ charCodeAt()
- ✅ codePointAt()
- ✅ indexOf()
- ✅ lastIndexOf()
- ✅ includes()
- ✅ startsWith()
- ✅ endsWith()
- ✅ concat()
- ✅ slice()
- ✅ substring()
- ✅ repeat()
- ✅ split() (solo string delimiters)
- ✅ replace() (solo strings literales)
- ✅ replaceAll() (solo strings literales)
- ✅ padStart()
- ✅ padEnd()
- ✅ trim()
- ✅ trimStart()
- ✅ trimEnd()
- ✅ Iterator (Symbol.iterator equivalente)
Total Fase 1: ~25 métodos
⚠️ toLowerCase() (Unicode completo)⚠️ toUpperCase() (Unicode completo)
⚠️ normalize()⚠️ isWellFormed()⚠️ toWellFormed()
⚠️ String.raw()
Total Fase 2: ~6 métodos
⚠️ match()⚠️ matchAll()⚠️ search()⚠️ split() (con regex)⚠️ replace() (con regex)⚠️ replaceAll() (con regex)
- ❌ toLocaleLowerCase()
- ❌ toLocaleUpperCase()
- ❌ localeCompare()
Total Fase 3: ~9 métodos (complejo)
- 🗑️ substr() - deprecated
- 🗑️ Todos los HTML wrappers (13 métodos)
- 🗑️ toString() / valueOf() (redundante en Zig)
// Opción A: Siempre retornar owned strings
pub fn concat(allocator: Allocator, strings: []const []const u8) ![]u8
// Opción B: Permitir opción de slice vs owned
pub fn slice(self: []const u8, start: isize, end: isize) []const u8
pub fn sliceOwned(allocator: Allocator, self: []const u8, start: isize, end: isize) ![]u8Decisión: Usar ambos patrones según el método
- Métodos que no modifican longitud: retornar slices
- Métodos que modifican/crean: requieren allocator
// Opción A: Siempre bytes (más rápido, menos compatible)
pub fn charAt(self: []const u8, index: usize) []const u8
// Opción B: Code points (más lento, más compatible con JS)
pub fn charAtCodePoint(self: []const u8, index: usize) []const u8
// Opción C: Ambos disponibles
pub fn byteAt(self: []const u8, byte_index: usize) u8
pub fn codePointAt(self: []const u8, cp_index: usize) u21Decisión: Proveer ambas variantes, documentar claramente
- Métodos con "byte" prefix: trabajan con bytes
- Métodos sin prefix: trabajan con code points (compatible JS)
- Documentar performance trade-offs
// ¿Qué hacer con bytes UTF-8 inválidos?
// Opción A: Error
pub fn codePointAt(self: []const u8, index: usize) !u21
// Opción B: Reemplazar con U+FFFD (�)
pub fn codePointAt(self: []const u8, index: usize) u21
// Opción C: Opción configurable
pub const Options = struct {
on_invalid: enum { err, replace, skip } = .replace,
};Decisión: Por defecto usar approach B (replacement)
- Más compatible con comportamiento de JS
- Métodos "strict" pueden retornar error
- isWellFormed() para validación previa
// Opción A: Namespace con funciones
const zstring = @import("zstring");
const result = zstring.toUpperCase(allocator, my_string);
// Opción B: Struct wrapper con métodos
const ZString = @import("zstring").ZString;
var zstr = try ZString.init(allocator, "hello");
defer zstr.deinit();
const upper = try zstr.toUpperCase();
// Opción C: Mixto (funciones + optional wrapper)
const zstring = @import("zstring");
// Uso directo
const upper1 = try zstring.toUpperCase(allocator, "hello");
// O con wrapper
var zstr = zstring.ZString{ .data = "hello" };
const upper2 = try zstr.toUpperCase(allocator);Decisión: Opción C (mixto)
- Funciones puras para casos simples
- Struct opcional para encadenar operaciones
- Mayor flexibilidad para el usuario
- Opciones:
- Investigar: Performance, compatibilidad ECMAScript, mantenimiento
- Zig stdlib: std.unicode (limitado pero suficiente para básico)
- Tablas Unicode: Generar desde UCD (Unicode Character Database)
- ICU bindings: Para locale-aware operations (Fase 3)
- Implementar con tablas generadas
- O bindings a biblioteca C existente
- ✅ Tests unitarios para cada método
- ✅ Tests de edge cases:
- Strings vacíos
- Índices negativos
- Índices fuera de rango
- UTF-8 multi-byte
- Emojis y caracteres especiales
- ✅ Tests de memoria (no leaks)
- ✅ Benchmarks de performance
- ✅ Tests de compatibilidad con JS (casos de uso comunes)
- Zig built-in test framework
- Fuzzing para robustez
- Memory sanitizers
Fase 1 (Core): Completamente viable, ~25 métodos esenciales
- Timeframe estimado: Base sólida y funcional
- Cubre 80% de casos de uso comunes
Fase 2 (Extended): Viable con esfuerzo moderado, ~6 métodos
- Requiere trabajo en Unicode correctness
- Mejora significativa en robustez
Fase 3 (Regex & Locale): Viable pero requiere dependencias externas
- Regex: Necesita biblioteca o implementación compleja
- Locale: Muy complejo, posiblemente no prioritario
- Comenzar con Fase 1: Crear API sólida y bien documentada
- Diseñar para extensibilidad: Dejar espacio para Fase 2 y 3
- Documentar diferencias con JS: Especialmente UTF-16 vs UTF-8
- Proveer ejemplos claros: Mostrar ownership y memoria explícita
- Tests exhaustivos: Garantizar correctness desde el inicio
- Definir estructura del proyecto
- Crear API sketch en código
- Implementar primeros métodos (charAt, indexOf, etc.)
- Establecer patterns de testing
- Iterar y expandir