Skip to main content

Funciones de string — referencia de Marketing Cloud AMPscript

Las operaciones de string disponibles en AMPscript — cada función con la indexación invertida (1-based, no 0-based), el comportamiento de replace-all-por-default, y el set chico de helpers de formato. Dónde diverge de SSJS y SQL, más los patrones que Cleon entrega.

Referencia·Actualizado 2026-05-13·Escrito por Lira · Editado por German Medina

El manejo de strings de AMPscript es todo funciones, sin operadores — no hay + para concatenación, no hay acceso a propiedad .length, no hay sintaxis con punto de método. Cada operación de string es una llamada a función: Concat(@a, @b), Length(@s), Substring(@s, 1, 5). La superficie de funciones es chica (alrededor de 20 operaciones de string), pero algunos comportamientos por default son inversos a lo que un programador de JavaScript o SQL espera: Substring e IndexOf son 1-based (no 0-based), y Replace reemplaza todas las ocurrencias por default (no solo la primera). La lista abajo es el inventario más los patrones que sobreviven a escala.

Sintaxis oficial

%%[
  VAR @email, @firstName, @cleaned, @greeting

  SET @email = AttributeValue("EmailAddress")
  SET @firstName = AttributeValue("FirstName")

  /* Length, acceso a caracteres */
  SET @len = Length(@email)              /* conteo de caracteres, no bytes */

  /* Search — 1-based, devuelve 0 cuando no encuentra */
  SET @atPos = IndexOf(@email, "@")      /* ej. 14 si email[14] es "@" */

  /* Slice — start 1-based, basado en largo (no end-exclusive) */
  SET @user = Substring(@email, 1, IndexOf(@email, "@") - 1)
  /* Para "ana@example.com": Substring(s, 1, 3) → "ana" */

  /* Case */
  SET @lowered = Lowercase(@email)
  SET @upped   = Uppercase(@firstName)
  SET @proper  = ProperCase(@firstName)  /* "JUAN" → "Juan" */

  /* Trimear whitespace (los dos lados) */
  SET @cleaned = Trim(@firstName)

  /* Replace — reemplaza TODAS las ocurrencias por default */
  SET @noDots = Replace(@email, ".", "_")     /* cada punto se vuelve underscore */
  SET @oneShot = Replace(@email, ".", "_", 1) /* 4to arg opcional: max reemplazos */

  /* Concat — variádico, toma 2+ args */
  SET @greeting = Concat("Hola, ", @firstName, "!")

  /* Reemplazo multi-valor */
  SET @safe = ReplaceList(@firstName, "_", "@", "%")
  /* reemplaza cualquiera de {@, %} con _ */
]%%

<p>%%=v(@greeting)=%%</p>

Helpers de formato:

%%[
  /* Format — estilo printf con args posicionales. {0}, {1}, ... */
  SET @msg = Format("Subscriber {0} pasó al tier {1}", @subKey, @tier)
  /* El Format de AMPscript toma args variádicos, NO un array (a diferencia de SSJS) */

  /* FormatNumber — formato de número locale-aware */
  SET @priceStr = FormatNumber(@price, "C", "es-AR")
  /* 1234.5 con "C" / "es-AR" → "$ 1.234,50" */

  /* FormatDate — formato de fecha locale-aware */
  SET @today = FormatDate(Now(), "yyyy-MM-dd")
  /* → "2026-05-13" */

  /* AsciiToChar / Char — carácter desde code point */
  SET @nl = Char(10)                  /* newline */
  SET @amp = AsciiToChar(38)          /* "&" */
]%%

El set soportado:

| Función | Qué hace | Notas | |---|---|---| | Length(s) | Conteo de caracteres | No byte count — Unicode-safe | | IndexOf(s, needle) | Posición del primer match | 1-based, devuelve 0 cuando no encuentra | | Substring(s, start, length) | Substring arrancando en start | 1-based; tercer arg es largo, no end index | | Lowercase(s) / Uppercase(s) | Case fold | | | ProperCase(s) | Title case del string | "JUAN PEREZ" → "Juan Perez" | | Trim(s) | Strip whitespace al inicio + al final | No hay LTrim / RTrim por separado | | Replace(s, find, replace [, count]) | Reemplaza ocurrencias | Reemplaza TODAS por default; 4to arg opcional capea el conteo | | ReplaceList(s, replacement, find1, find2, ...) | Reemplaza múltiples needles con un solo replacement | Variádico | | Concat(s1, s2, ...) | Concatena strings | Variádico; no hay operador + | | Char(code) | Carácter desde int code | Útil para newlines, chars especiales | | AsciiToChar(code) | Carácter desde ASCII code | Igual que Char para el rango ASCII | | Format(template, arg1, arg2, ...) | Estilo printf con {0}, {1} placeholders | Args variádicos (a diferencia de SSJS que toma un array) | | FormatNumber(n, fmt, locale) | Formato de número locale-aware | "C" (currency), "N2", "P", etc. | | FormatDate(d, fmt [, locale]) | Formato de fecha locale-aware | Devuelve string | | RegExMatch(s, pattern, group) | Match de regex — superficie limitada | No está disponible en todos los tenants | | StringToDate(s) | Parsear string a fecha | Reglas de parsing flexibles | | StringToHex(s) | String a representación hex | Útil para encodings de tracking pixels |

Referencia:

Lo que sobrevive en producción

Substring e IndexOf son 1-based — el bug off-by-one que se envía

Los devs de JavaScript, Python y Go agarran Substring(@s, 0, 3) y obtienen un resultado confuso. En AMPscript:

  • Substring(@s, 1, 3) devuelve los primeros tres caracteres.
  • Substring(@s, 0, 3) devuelve un string vacío o se comporta indefinido según el tenant — nunca los primeros tres.
%%[
  SET @s = "Mariana"

  /* MAL — silenciosamente devuelve "" o "Mar" según la versión del tenant */
  SET @firstThree = Substring(@s, 0, 3)

  /* BIEN — start 1-based, conteo basado en largo */
  SET @firstThree = Substring(@s, 1, 3)   /* → "Mar" */

  /* "Traeme todo desde la posición 5 en adelante" */
  SET @tail = Substring(@s, 5, Length(@s))
  /* → "ana" (largo extra está bien, MC trunca al final del string) */
]%%

IndexOf sigue la misma convención — 1-based cuando encuentra, 0 cuando no encuentra:

%%[
  SET @email = "ana@example.com"

  SET @atPos = IndexOf(@email, "@")    /* → 4 (1-based) */
  SET @nope  = IndexOf(@email, "?")    /* → 0 (no encontrado) */

  /* Lógica condicional — atención a la comparación */
  IF IndexOf(@email, "@") > 0 THEN
    /* encontrado — igual que el check "> 0" en el CHARINDEX de SQL */
  ENDIF
]%%

Este es el inverso del indexOf de SSJS / JavaScript, que devuelve -1 cuando no encuentra y 0 cuando encuentra en posición 0. La falla del hand-off: un dev copia un patrón JS de parsing de strings, swapea los nombres de función a equivalentes AMPscript, y rompe la condicional en silencio. Ver gotchas — #7.

Replace reemplaza todas las ocurrencias por default

Lo opuesto a JavaScript y SSJS, donde .replace("x", "y") reemplaza solo el primer match salvo que pases un regex con /g. AMPscript reemplaza todo por default — pasale un 4to argumento para capear el conteo.

%%[
  SET @s = "a,b,c,d"

  /* Reemplaza TODAS las comas — usualmente lo que querés */
  SET @piped = Replace(@s, ",", "|")          /* → "a|b|c|d" */

  /* Reemplazar solo la primera coma */
  SET @oneShot = Replace(@s, ",", "|", 1)     /* → "a|b,c,d" */
]%%

La falla del hand-off corre al revés: un dev que viene de JS agrega Replace(@s, ",", "|") pensando que solo maneja el primer match, después se sorprende cuando el output es correcto. Menos dañino que la dirección inversa, pero vale la pena saberlo para code review.

Concat es variádico — sin operador +

No hay + para strings. Usá Concat para todo.

%%[
  SET @firstName = "Mariana"

  /* MAL — AMPscript no parsea + como concat de string */
  SET @greeting = "Hola, " + @firstName + "!"

  /* BIEN — Concat maneja 2+ args */
  SET @greeting = Concat("Hola, ", @firstName, "!")
]%%

Para 4+ pedazos, Concat se lee mejor que llamadas anidadas. El patrón Cleon: construí el string en una sola llamada a Concat cuando se lee bien, fallback a una secuencia de SET @x = Concat(@x, ...) cuando las condiciones tienen que ramificar el armado:

%%[
  SET @line = Concat("Orden #", @orderId, " — ", @itemName)
  IF NOT Empty(@discount) THEN
    SET @line = Concat(@line, " (", @discount, "% off)")
  ENDIF
]%%

Trim existe — pero no hay LTrim / RTrim por separado

AMPscript trae Trim que pela los dos lados. No hay built-in para trimear solo un lado. Usá Substring con IndexOf si necesitás comportamiento de un solo lado — es lo suficientemente raro como para que la forma verbosa esté bien.

%%[
  /* Trim los dos lados — caso común */
  SET @clean = Trim(@firstName)

  /* Trim solo el lado derecho (raro) — sin built-in */
  /* Si tu input tiene whitespace al final por un import de data,
     arreglalo en la SQL Activity upstream donde existen las funciones TRIM. */
]%%

Empty(Concat(...)) es true si cualquier arg es NULL

Concat con un arg NULL produce un string con el NULL coerceado a vacío — el resultado es igual un string, pero visualmente la concatenación tiene un agujero. Peor, si todos los args son NULL, el resultado es el string vacío y Empty() devuelve true.

%%[
  SET @firstName = AttributeValue("FirstName")  /* puede ser NULL */
  SET @greeting = Concat("Hola, ", @firstName, "!")
  /* Si @firstName es NULL → "Hola, !" — visualmente roto */

  /* DURABLE — defaulteá la var antes del concat */
  IF Empty(@firstName) THEN
    SET @firstName = "Friend"
  ENDIF
  SET @greeting = Concat("Hola, ", @firstName, "!")
]%%

Esta es la versión AMPscript de la falla "el + de SSJS coercea NULL a literal 'null'" — misma forma, output ligeramente distinto. La defensa es la misma: defaulteá cada variable que alimenta una concatenación, cada vez.

Format toma args variádicos, no un array

Una diferencia chica pero importante con SSJS donde Platform.Function.Format toma un array. En AMPscript, los args son posicionales después del template.

%%[
  /* Forma AMPscript — variádico */
  SET @msg = Format("User {0} ({1}) en tier {2}", @user, @email, @tier)

  /* Forma SSJS para comparar — args como array */
  /* SSJS: Platform.Function.Format("User {0} ({1})", [user, email]) */
]%%

Hasta ~10 args posicionales está bien; más allá te conviene armar el string con Concat y variables nombradas para legibilidad.

FormatNumber y FormatDate son locale-aware — el preview miente sobre el locale

El tercer arg de FormatNumber y FormatDate es un string de locale ("en-US", "es-AR", etc.). El locale afecta separadores decimales, símbolos de moneda, formatos de fecha.

%%[
  SET @price = 1234.5
  SET @us = FormatNumber(@price, "C", "en-US")  /* → "$1,234.50" */
  SET @ar = FormatNumber(@price, "C", "es-AR")  /* → "$ 1.234,50" */

  SET @today = Now()
  SET @usDate = FormatDate(@today, "MM/dd/yyyy")        /* → "05/13/2026" */
  SET @arDate = FormatDate(@today, "dd/MM/yyyy")        /* → "13/05/2026" */
]%%

La trampa: el preview de personalización de Email Studio puede usar un locale distinto al del envío de producción. Un preview que renderea $1,234.50 puede mandar $ 1.234,50 para un destinatario en Argentina, o viceversa. Test sends a un subscriber real en el locale destino antes de asumir que el formato está bien. Ver gotchas — #9.

Decisión rápida

Usá Substring cuando:

  • Extraés una porción de posición fija de un string (primeros N chars, últimos N chars, slice entre dos índices conocidos).

Usá IndexOf y después Substring cuando:

  • El slice depende de encontrar un delimitador — split en @ para emails, etc. No hay un Split() nativo en AMPscript.

Usá Replace cuando:

  • Sustituís un solo valor a lo largo del string. El comportamiento default (reemplazar-todo) suele ser lo que querés; capealo con el 4to arg solo cuando hace falta.

Usá Concat cuando:

  • Construís cualquier string de 2+ partes. No hay alternativa con +.

Usá Format cuando:

  • Construís un string con 2+ valores interpolados que comparten un solo template.

Usá FormatNumber / FormatDate cuando:

  • El output va a un subscriber y el locale importa. Siempre testeá en el locale destino.

Hacé el trabajo en SQL en su lugar cuando:

  • Necesitás regex más allá del match simple. Pre-formateá upstream.
  • Necesitás splitear sobre un delimitador y acceder partes individuales. Pre-computá en SQL.
  • La misma transformación corre per-destinatario en un send grande. Una corrida SQL le gana a N corridas AMPscript.

Relacionado

Más páginas de referencia AMPscript en camino: funciones de Date · Math · Validación · Data Extension · Subscriber/Profile · Cloud-write · Encoding/Hashing · Style Guide.