Stringable
Stringable
Sección titulada «Stringable»La clase Stringable es un envoltorio fluido e inmutable sobre el tipo str nativo de Python. Proporciona una amplia colección de métodos encadenables para operaciones comunes con cadenas — búsqueda, reemplazo, transformación de mayúsculas/minúsculas, codificación, validación y más — sin mutar el valor original. Al extender str, puede usarse en cualquier lugar donde se acepte una cadena regular, agregando la conveniencia expresiva de nivel framework.
Importación
Sección titulada «Importación»from orionis.support.strings.stringable import StringableCreación de una Instancia
Sección titulada «Creación de una Instancia»s = Stringable("Hello World")Cada método que retorna texto produce una nueva instancia de Stringable, lo que permite encadenar llamadas de forma fluida:
result = Stringable(" hello world ").trim().title().finish("!")# "Hello World!"Extracción de Subcadenas
Sección titulada «Extracción de Subcadenas»after / afterLast
Sección titulada «after / afterLast»Retorna la porción de la cadena después de la primera (o última) aparición de un delimitador.
Stringable("foo/bar/baz").after("/") # "bar/baz"Stringable("foo/bar/baz").afterLast("/") # "baz"Si el delimitador no se encuentra, se retorna la cadena original.
before / beforeLast
Sección titulada «before / beforeLast»Retorna la porción de la cadena antes de la primera (o última) aparición de un delimitador.
Stringable("foo/bar/baz").before("/") # "foo"Stringable("foo/bar/baz").beforeLast("/") # "foo/bar"between / betweenFirst
Sección titulada «between / betweenFirst»Extrae el texto entre dos delimitadores. between utiliza la primera aparición del delimitador de inicio y la primera aparición del delimitador de fin después de este. betweenFirst se comporta de forma idéntica y se ofrece por legibilidad.
Stringable("[hello]").between("[", "]") # "hello"Stringable("[a][b]").betweenFirst("[", "]") # "a"Retorna un Stringable vacío cuando alguno de los delimitadores no se encuentra.
Retorna una subcadena a partir de una posición dada, opcionalmente limitada a una longitud específica.
Stringable("Hello World").substr(6) # "World"Stringable("Hello World").substr(0, 5) # "Hello"Toma caracteres desde el inicio (positivo) o el final (negativo) de la cadena.
Stringable("hello world").take(5) # "hello"Stringable("hello world").take(-5) # "world"excerpt
Sección titulada «excerpt»Extrae un fragmento alrededor de la primera aparición de una frase, con radio y texto de omisión configurables.
text = Stringable("The quick brown fox jumps over the lazy dog")text.excerpt("fox", {"radius": 5, "omission": "..."})# "...brown fox jumps..."Retorna None si la frase no se encuentra.
Búsqueda y Posición
Sección titulada «Búsqueda y Posición»contains
Sección titulada «contains»Verifica si la cadena contiene una o más subcadenas. Acepta una cadena individual o un iterable, con flag opcional de búsqueda sin distinción de mayúsculas.
Stringable("Hello World").contains("World") # TrueStringable("Hello World").contains("world", ignore_case=True) # TrueStringable("Hello World").contains(["foo", "World"]) # TruecontainsAll
Sección titulada «containsAll»Retorna True solo cuando todas las agujas de la lista están presentes.
Stringable("hello world foo").containsAll(["hello", "world", "foo"]) # TrueStringable("hello world").containsAll(["hello", "xyz"]) # FalsedoesntContain
Sección titulada «doesntContain»El inverso de contains.
Stringable("hello world").doesntContain("xyz") # TruestartsWith / endsWith
Sección titulada «startsWith / endsWith»Stringable("hello.py").endsWith(".py") # TrueStringable("hello.py").endsWith([".py", ".txt"]) # TrueStringable("hello world").startsWith("hello") # TruedoesntStartWith / doesntEndWith
Sección titulada «doesntStartWith / doesntEndWith»Stringable("hello").doesntStartWith("world") # TrueStringable("hello.py").doesntEndWith(".txt") # Trueexactly
Sección titulada «exactly»Comparación de igualdad estricta.
Stringable("hello").exactly("hello") # TrueStringable("hello").exactly("Hello") # Falseposition
Sección titulada «position»Encuentra el índice de la primera aparición de una subcadena, opcionalmente comenzando desde un desplazamiento. Retorna False si no se encuentra.
Stringable("hello world").position("world") # 6Stringable("hello world").position("xyz") # Falsematch / matchAll / isMatch / test
Sección titulada «match / matchAll / isMatch / test»Métodos auxiliares para expresiones regulares:
Stringable("order-1234").match(r"\d+") # "1234"Stringable("a1b2c3").matchAll(r"\d") # ["1", "2", "3"]Stringable("hello").isMatch(r"^h.*o$") # TrueStringable("hello").test(r"^h.*o$") # True (alias)isPattern
Sección titulada «isPattern»Coincidencia basada en comodines (* y ?), con modo sin distinción de mayúsculas opcional.
Stringable("hello world").isPattern("hello*") # TrueStringable("Hello World").isPattern("hello*", ignore_case=True) # TrueReemplazo
Sección titulada «Reemplazo»replace
Sección titulada «replace»Reemplaza subcadenas con nuevos valores. Soporta listas paralelas para multi-reemplazo y modo sin distinción de mayúsculas.
Stringable("Hello World").replace("World", "Python") # "Hello Python"Stringable("Hello World").replace("world", "Python", case_sensitive=False) # "Hello Python"Stringable("a b c").replace(["a", "b"], ["x", "y"]) # "x y c"replaceFirst / replaceLast
Sección titulada «replaceFirst / replaceLast»Reemplaza solo la primera o última aparición.
Stringable("aaa").replaceFirst("a", "b") # "baa"Stringable("aaa").replaceLast("a", "b") # "aab"replaceStart / replaceEnd
Sección titulada «replaceStart / replaceEnd»Reemplaza una subcadena solo si aparece como prefijo o sufijo.
Stringable("helloWorld").replaceStart("hello", "hi") # "hiWorld"Stringable("helloWorld").replaceEnd("World", "Python") # "helloPython"replaceArray
Sección titulada «replaceArray»Reemplaza apariciones de una cadena de búsqueda una a una con elementos sucesivos de una lista.
Stringable("? ? ?").replaceArray("?", ["a", "b", "c"]) # "a b c"replaceMatches
Sección titulada «replaceMatches»Reemplazo basado en regex con una cadena o un callable.
Stringable("hello123world").replaceMatches(r"\d+", "NUM")# "helloNUMworld"
Stringable("hello").replaceMatches(r"[aeiou]", lambda m: m.group(0).upper())# "hEllO"Elimina subcadenas completamente.
Stringable("hello world").remove("l") # "heo word"Stringable("Hello World").remove("hello", case_sensitive=False) # " World"Stringable("hello world").remove(["hello", " "]) # "world"Reemplaza múltiples palabras clave usando un diccionario de mapeo.
Stringable("I love cats").swap({"cats": "dogs"}) # "I love dogs"Conversión de Mayúsculas/Minúsculas
Sección titulada «Conversión de Mayúsculas/Minúsculas»lower / upper
Sección titulada «lower / upper»Stringable("HELLO World").lower() # "hello world"Stringable("hello World").upper() # "HELLO WORLD"swapCase
Sección titulada «swapCase»Invierte las mayúsculas/minúsculas de cada carácter.
Stringable("Hello World").swapCase() # "hELLO wORLD"camel / kebab / snake / studly / pascal
Sección titulada «camel / kebab / snake / studly / pascal»Convierte entre convenciones de nomenclatura comunes.
Stringable("hello_world").camel() # "helloWorld"Stringable("helloWorld").kebab() # "hello-world"Stringable("helloWorld").snake() # "hello_world"Stringable("helloWorld").snake(".") # "hello.world"Stringable("hello_world").studly() # "HelloWorld"Stringable("hello_world").pascal() # "HelloWorld" (alias de studly)title / headline / apa
Sección titulada «title / headline / apa»Stringable("hello world").title() # "Hello World"Stringable("hello world").headline() # "Hello World"
Stringable("the quick brown fox").apa()# "The Quick Brown Fox" — Estilo APA: palabras cortas en minúsculas excepto primera/últimaucfirst / lcfirst
Sección titulada «ucfirst / lcfirst»Convierte a mayúscula o minúscula solo el primer carácter.
Stringable("hello world").ucfirst() # "Hello world"Stringable("Hello World").lcfirst() # "hello World"convertCase
Sección titulada «convertCase»Conversión basada en modo numérico:
| Modo | Efecto |
|---|---|
None / 0 | casefold |
1 | MAYÚSCULAS |
2 | minúsculas |
3 | Título |
Stringable("HELLO").convertCase(2) # "hello"Genera un slug amigable para URLs. Soporta un separador personalizado y un diccionario de reemplazo de caracteres.
Stringable("Hello World!").slug() # "hello-world"Stringable("Hello World").slug("_") # "hello_world"Stringable("user@example").slug() # "user-at-example"Recorte y Relleno
Sección titulada «Recorte y Relleno»trim / ltrim / rtrim
Sección titulada «trim / ltrim / rtrim»Stringable(" hello ").trim() # "hello"Stringable("--hello--").trim("-") # "hello"Stringable(" hello ").ltrim() # "hello "Stringable(" hello ").rtrim() # " hello"lStrip / rStrip
Sección titulada «lStrip / rStrip»Envoltorios estilo Python para lstrip / rstrip que retornan un Stringable.
Stringable("xxhello").lStrip("x") # "hello"Stringable("helloxx").rStrip("x") # "hello"padBoth / padLeft / padRight
Sección titulada «padBoth / padLeft / padRight»Rellena la cadena para alcanzar una longitud total deseada.
Stringable("hi").padBoth(6) # " hi "Stringable("hi").padLeft(5) # " hi"Stringable("5").padLeft(3, "0") # "005"Stringable("hi").padRight(5) # "hi "Rellena con ceros a la izquierda.
Stringable("42").zFill(5) # "00042"Colapsa espacios en blanco consecutivos en un solo espacio y recorta.
Stringable(" hello world ").squish() # "hello world"deduplicate
Sección titulada «deduplicate»Colapsa apariciones consecutivas de un carácter en una sola.
Stringable("hello world").deduplicate() # "hello world"Stringable("aabbcc").deduplicate("b") # "aabcc"Construcción y Envolvimiento
Sección titulada «Construcción y Envolvimiento»append / prepend
Sección titulada «append / prepend»Stringable("hello").append(" world", "!") # "hello world!"Stringable("world").prepend("hello ", "dear ") # "hello dear world"newLine
Sección titulada «newLine»Agrega uno o más caracteres de nueva línea.
Stringable("hello").newLine() # "hello\n"Stringable("hello").newLine(2) # "hello\n\n"finish / start
Sección titulada «finish / start»Asegura que la cadena termina (o comienza) con un valor dado — no lo duplica si ya está presente.
Stringable("path/to").finish("/") # "path/to/"Stringable("path/to/").finish("/") # "path/to/"Stringable("world").start("hello ") # "hello world"wrap / unwrap
Sección titulada «wrap / unwrap»Stringable("hello").wrap('"') # '"hello"'Stringable("hello").wrap("[", "]") # "[hello]"Stringable('"hello"').unwrap('"') # "hello"Stringable("[hello]").unwrap("[", "]") # "hello"Stringable("ab").repeat(3) # "ababab"Stringable("ab").repeat(0) # ""reverse
Sección titulada «reverse»Stringable("hello").reverse() # "olleh"Limitación y Truncamiento
Sección titulada «Limitación y Truncamiento»Trunca la cadena a un número máximo de caracteres. Un flag opcional preserve_words evita cortar a mitad de palabra.
Stringable("hello world").limit(5) # "hello..."Stringable("hello world").limit(5, " [more]") # "hello [more]"Stringable("hello world foo").limit(8, "...", preserve_words=True) # truncamiento seguro por palabrasLimita a un número máximo de palabras.
Stringable("one two three four").words(2) # "one two..."Enmascara una porción de la cadena con un carácter repetido.
Stringable("password").mask("*", 2, 4) # "pa****rd"Stringable("hello").mask("*", 2) # "he***"Stringable("hello").mask("*", -3) # "he***"División
Sección titulada «División»explode
Sección titulada «explode»Divide por un delimitador literal.
Stringable("a,b,c").explode(",") # ["a", "b", "c"]Divide por una expresión regular o por longitud de fragmento.
Stringable("a1b2c3").split(r"\d") # ["a", "b", "c", ""]Stringable("abcdef").split(2) # ["ab", "cd", "ef"]ucsplit
Sección titulada «ucsplit»Divide en las fronteras de mayúsculas.
Stringable("helloWorld").ucsplit() # ["hello", "World"]Stringable("hello").length() # 5wordCount
Sección titulada «wordCount»Stringable("hello world").wordCount() # 2substrCount
Sección titulada «substrCount»Cuenta apariciones no superpuestas de una subcadena, opcionalmente dentro de una ventana offset/length.
Stringable("banana").substrCount("an") # 2Ajuste de Texto
Sección titulada «Ajuste de Texto»wordWrap
Sección titulada «wordWrap»Ajusta el texto a un ancho de línea especificado.
long_text = Stringable("This is a long sentence that needs wrapping")long_text.wordWrap(20)Codificación y Hashing
Sección titulada «Codificación y Hashing»toBase64 / fromBase64
Sección titulada «toBase64 / fromBase64»Stringable("hello").toBase64() # "aGVsbG8="Stringable("aGVsbG8=").fromBase64() # "hello"fromBase64 acepta un parámetro solo por nombre strict. Cuando strict=True, una entrada inválida lanza un RuntimeError en lugar de retornar una cadena vacía.
md5 / sha1 / sha256
Sección titulada «md5 / sha1 / sha256»Métodos de hashing convenientes que retornan cadenas de resumen hexadecimal.
Stringable("hello").md5() # resumen hex de 32 caracteresStringable("hello").sha1() # resumen hex de 40 caracteresStringable("hello").sha256() # resumen hex de 64 caracteresAplica hash con cualquier algoritmo soportado por hashlib.
Stringable("hello").hash("sha256") # equivalente a .sha256()toHtmlString / stripTags
Sección titulada «toHtmlString / stripTags»Stringable("<b>Hello</b>").toHtmlString() # "<b>Hello</b>"Stringable("<p>Hello <b>World</b></p>").stripTags() # "Hello World"ascii / transliterate
Sección titulada «ascii / transliterate»Elimina o reemplaza caracteres no ASCII.
Stringable("café").ascii() # "cafe"Stringable("café").transliterate("?", strict=True) # "caf?"encrypt / decrypt
Sección titulada «encrypt / decrypt»Cifra y descifra mediante la fachada Crypt del framework. Requiere que el servicio Encrypter esté registrado.
encrypted = Stringable("secret").encrypt()decrypted = encrypted.decrypt()Conversión de Tipos
Sección titulada «Conversión de Tipos»toInteger / toFloat / toBoolean
Sección titulada «toInteger / toFloat / toBoolean»Stringable("42").toInteger() # 42Stringable("0xff").toInteger(16) # 255Stringable("3.14").toFloat() # 3.14Stringable("true").toBoolean() # TrueStringable("0").toBoolean() # FalseRetorna el str plano subyacente.
Stringable("hello").value() # "hello" (tipo: str)jsonSerialize
Sección titulada «jsonSerialize»Retorna un str plano apto para codificación JSON.
Stringable("hello").jsonSerialize() # "hello"Validación
Sección titulada «Validación»isEmpty / isNotEmpty
Sección titulada «isEmpty / isNotEmpty»Stringable("").isEmpty() # TrueStringable("hello").isNotEmpty() # TrueVerificaciones de Tipo de Carácter
Sección titulada «Verificaciones de Tipo de Carácter»| Método | Retorna True cuando… |
|---|---|
isAlnum() | Todos los caracteres son alfanuméricos |
isAlpha() | Todos los caracteres son alfabéticos |
isDecimal() | Todos los caracteres son dígitos decimales |
isDigit() | Todos los caracteres son dígitos |
isIdentifier() | Es un identificador Python válido |
isLower() | Todos los caracteres con casing están en minúsculas |
isUpper() | Todos los caracteres con casing están en mayúsculas |
isNumeric() | Todos los caracteres son numéricos |
isPrintable() | Todos los caracteres son imprimibles |
isSpace() | Solo caracteres de espacio en blanco |
isTitle() | Cadena en formato título |
isAscii() | Solo caracteres ASCII de 7 bits |
Stringable('{"key": "value"}').isJson() # TrueStringable("not json").isJson() # FalseValida una URL, opcionalmente restringiendo a protocolos específicos.
Stringable("https://example.com").isUrl() # TrueStringable("ftp://example.com").isUrl(protocols=["ftp"]) # TrueisUuid / isUlid
Sección titulada «isUuid / isUlid»Stringable("550e8400-e29b-41d4-a716-446655440000").isUuid() # TrueStringable("550e8400-e29b-41d4-a716-446655440000").isUuid(4) # True (versión 4)Stringable("01ARZ3NDEKTSV4RRFFQ69G5FAV").isUlid() # TruePluralización
Sección titulada «Pluralización»plural / singular
Sección titulada «plural / singular»Reglas básicas de pluralización del inglés.
Stringable("cat").plural() # "cats"Stringable("cat").plural(1) # "cat"Stringable("baby").plural() # "babies"Stringable("bus").plural() # "buses"Stringable("cat").plural(3, prepend_count=True) # "3 cats"
Stringable("cats").singular() # "cat"Stringable("babies").singular() # "baby"pluralStudly / pluralPascal
Sección titulada «pluralStudly / pluralPascal»Pluraliza la última palabra de una cadena en StudlyCase o PascalCase.
Stringable("BlogPost").pluralStudly() # "BlogPosts"Stringable("UserProfile").pluralPascal() # "UserProfiles"Análisis de Callbacks
Sección titulada «Análisis de Callbacks»parseCallback
Sección titulada «parseCallback»Analiza una cadena estilo Class@method en sus componentes.
Stringable("MyClass@myMethod").parseCallback() # ["MyClass", "myMethod"]Stringable("MyClass").parseCallback("handle") # ["MyClass", "handle"]Stringable("MyClass").parseCallback() # ["MyClass", None]Utilidades de Rutas
Sección titulada «Utilidades de Rutas»basename / dirname
Sección titulada «basename / dirname»Stringable("/home/user/file.txt").basename() # "file.txt"Stringable("/home/user/file.txt").basename(".txt") # "file"Stringable("/home/user/file.txt").dirname() # "/home/user"Acceso por Posición
Sección titulada «Acceso por Posición»offsetExists / offsetGet / charAt
Sección titulada «offsetExists / offsetGet / charAt»Stringable("hello").offsetExists(2) # TrueStringable("hello").offsetExists(99) # FalseStringable("hello").offsetGet(1) # "e"Stringable("hello").charAt(0) # "h"Stringable("hello").charAt(99) # FalseStringable también soporta indexación y slicing estándar:
Stringable("hello")[1] # Stringable("e")Stringable("hello")[1:4] # Stringable("ell")Extracción Numérica
Sección titulada «Extracción Numérica»numbers
Sección titulada «numbers»Elimina todos los caracteres no numéricos.
Stringable("phone: +1-234-567").numbers() # "1234567"Extrae valores usando un formato simplificado estilo sscanf con los marcadores %s, %d y %f.
Stringable("John 30 5.9").scan("%s %d %f") # ["John", "30", "5.9"]Reemplazo de Subcadenas
Sección titulada «Reemplazo de Subcadenas»substrReplace
Sección titulada «substrReplace»Reemplaza texto dentro de un rango específico de la cadena usando offset y longitud.
Stringable("hello world").substrReplace("Python", 6, 5) # "hello Python"Ejecución Condicional
Sección titulada «Ejecución Condicional»Todos los métodos when* aceptan un callback y un default opcional. El callback recibe el Stringable actual y su valor de retorno se convierte en la nueva cadena. Si la condición es False y no se proporciona default, se retorna la cadena original sin cambios.
Ejecuta un callback condicionalmente basado en una condición booleana o callable.
Stringable("hello").when(True, lambda s: s.upper()) # "HELLO"Stringable("hello").when(False, lambda s: s.upper()) # "hello"Stringable("hello").when(lambda s: s.isNotEmpty(), lambda s: s.upper()) # "HELLO"whenContains / whenContainsAll
Sección titulada «whenContains / whenContainsAll»Stringable("hello world").whenContains("world", lambda s: s.upper())# "HELLO WORLD"whenEmpty / whenNotEmpty
Sección titulada «whenEmpty / whenNotEmpty»Stringable("").whenEmpty(lambda s: Stringable("default")) # "default"Stringable("hello").whenNotEmpty(lambda s: s.upper()) # "HELLO"whenStartsWith / whenDoesntStartWith
Sección titulada «whenStartsWith / whenDoesntStartWith»Stringable("hello world").whenStartsWith("hello", lambda s: s.upper())# "HELLO WORLD"whenEndsWith / whenDoesntEndWith
Sección titulada «whenEndsWith / whenDoesntEndWith»Stringable("hello.py").whenEndsWith(".py", lambda s: s.upper())# "HELLO.PY"whenExactly / whenNotExactly
Sección titulada «whenExactly / whenNotExactly»Stringable("hello").whenExactly("hello", lambda s: s.upper()) # "HELLO"Stringable("hello").whenNotExactly("world", lambda s: s.upper()) # "HELLO"whenTest / whenIs / whenIsAscii / whenIsUuid / whenIsUlid
Sección titulada «whenTest / whenIs / whenIsAscii / whenIsUuid / whenIsUlid»Stringable("hello123").whenTest(r"\d+", lambda s: s.upper()) # "HELLO123"Pipelines y Efectos Secundarios
Sección titulada «Pipelines y Efectos Secundarios»Pasa la cadena a través de un callback y retorna el resultado.
Stringable("hello").pipe(lambda s: s.upper()) # "HELLO"Ejecuta un callback de efecto secundario sin modificar la cadena. Útil para logging o depuración dentro de una cadena de llamadas.
Stringable("hello").tap(lambda s: print(s)).upper() # imprime "hello", retorna "HELLO"Análisis de Fechas
Sección titulada «Análisis de Fechas»Convierte la cadena en un objeto datetime usando el formato especificado (por defecto %Y-%m-%d). El datetime resultante incluye zona horaria usando la zona local del framework.
Stringable("2026-04-01").toDate() # datetime(2026, 4, 1, ...)Stringable("01/04/2026").toDate("%d/%m/%Y") # datetime(2026, 4, 1, ...)Lanza ValueError si la cadena no coincide con el formato.