Una cadena literal o cadena anónima es un literal para un valor de cadena en el código fuente de un programa informático. Los lenguajes de programación modernos suelen utilizar una secuencia de caracteres entre comillas, formalmente "delimitadores entre corchetes", como en x = "foo"
, donde , "foo"
es una cadena literal con valor foo
. Se pueden utilizar métodos como secuencias de escape para evitar el problema de la colisión de delimitadores (problemas con los corchetes) y permitir que los delimitadores se incorporen en una cadena. Hay muchas notaciones alternativas para especificar literales de cadena, especialmente en casos complicados. La notación exacta depende del lenguaje de programación en cuestión. Sin embargo, existen pautas generales que siguen la mayoría de los lenguajes de programación modernos.
La mayoría de los lenguajes de programación modernos utilizan delimitadores de corchetes (también denominados delimitadores equilibrados ) para especificar cadenas literales. Las comillas dobles son los delimitadores de comillas más comunes:
"¡Hola!"
Una cadena vacía se escribe literalmente mediante un par de comillas sin ningún carácter entre ellas:
""
Algunos idiomas permiten o exigen el uso de comillas simples en lugar de comillas dobles (la cadena debe comenzar y terminar con el mismo tipo de comillas y el tipo de comillas puede o no generar una semántica ligeramente diferente):
'¡Hola!'
Estas comillas no están emparejadas (se utiliza el mismo carácter para abrir y cerrar), lo que es un vestigio de la tecnología de la máquina de escribir , que fue la precursora de los primeros dispositivos de entrada y salida de las computadoras.
En términos de expresiones regulares , una cadena literal entre comillas básica se proporciona como:
"[^"]*"
Esto significa que una cadena literal se escribe como: una comilla, seguida de cero, uno o más caracteres que no sean comillas, seguida de una comilla . En la práctica, esto suele complicarse con el uso de caracteres de escape, otros delimitadores y la exclusión de nuevas líneas.
Varios lenguajes permiten utilizar delimitadores emparejados, en los que los delimitadores de apertura y cierre son diferentes. Estos también suelen permitir cadenas anidadas, por lo que se pueden incrustar delimitadores, siempre que estén emparejados, pero aún así se produce una colisión de delimitadores por incrustar un delimitador de cierre no emparejado. Algunos ejemplos son PostScript , que utiliza paréntesis, como en (The quick (brown fox))
y m4 , que utiliza la comilla invertida (`) como delimitador de inicio y el apóstrofo (') como delimitador de cierre. Tcl permite tanto comillas (para cadenas interpoladas) como llaves (para cadenas sin formato), como en "The quick brown fox"
or {The quick {brown fox}}
; esto se deriva de las comillas simples en los shells de Unix y del uso de llaves en C para declaraciones compuestas, ya que los bloques de código son en Tcl sintácticamente lo mismo que los literales de cadena: que los delimitadores estén emparejados es esencial para que esto sea posible.
El conjunto de caracteres Unicode incluye versiones emparejadas (apertura y cierre separados) de comillas simples y dobles:
"¡Hola!" '¡Hola!' "¡Hola!" "¡Hola!"
Sin embargo, rara vez se utilizan, ya que muchos lenguajes de programación no los registran (una excepción son las comillas dobles pareadas que se pueden usar en Visual Basic .NET ). Se prefieren las comillas no pareadas por cuestiones de compatibilidad, ya que son más fáciles de escribir en una amplia gama de teclados y, por lo tanto, incluso en los lenguajes donde se permiten, muchos proyectos prohíben su uso para el código fuente.
Las cadenas literales pueden finalizar con nuevas líneas.
Un ejemplo son los parámetros de plantilla de MediaWiki .
{{Cuadro de navegación |nombre=Nulos |title=[[wikt:Null|Nulos]] en [[informática]] }}
Podría haber una sintaxis especial para cadenas de varias líneas.
En YAML , los literales de cadena se pueden especificar mediante la posición relativa de los espacios en blanco y la sangría.
- título : Ejemplo de cadena de varias líneas en el cuerpo de YAML : | Esta es una cadena de varias líneas. Aquí pueden aparecer metacaracteres "especiales" . La extensión de esta cadena se representa mediante sangría.
Algunos lenguajes de programación, como Perl y PHP, permiten cadenas literales sin ningún delimitador en algunos contextos. En el siguiente programa Perl, por ejemplo, red
, green
y blue
son cadenas literales, pero no están entre comillas:
%map = ( rojo => 0x00f , azul => 0x0f0 , verde => 0xf00 );
Perl trata las secuencias no reservadas de caracteres alfanuméricos como cadenas literales en la mayoría de los contextos. Por ejemplo, las dos líneas siguientes de Perl son equivalentes:
$y = "x" ; $y = x ;
En el lenguaje de programación original FORTRAN (por ejemplo), los literales de cadena se escribían en la llamada notación Hollerith , donde un recuento decimal del número de caracteres era seguido por la letra H, y luego los caracteres de la cadena:
35 HUn ejemplo de literal de cadena Hollerith
Este estilo de notación declarativa contrasta con las comillas delimitadoras , porque no requiere el uso de caracteres "entre corchetes" equilibrados en ambos lados de la cadena.
Ventajas:
Desventajas:
Sin embargo, esto no es un inconveniente cuando el prefijo se genera mediante un algoritmo, como es muy probable que sea el caso. [ cita requerida ]
C++ tiene dos estilos de cadena, uno heredado de C (delimitado por "
) y el más seguro std::string
de la biblioteca estándar de C++. La std::string
clase se utiliza con frecuencia de la misma manera que se utilizaría una cadena literal en otros lenguajes y, a menudo, se prefiere a las cadenas de estilo C por su mayor flexibilidad y seguridad. Pero conlleva una penalización de rendimiento para las cadenas literales, ya que std::string
normalmente asigna memoria de forma dinámica y debe copiar la cadena literal de estilo C en ella en tiempo de ejecución.
Antes de C++11, no existían literales para cadenas de C++ (C++11 permite "this is a C++ string"s
usar el s
al final del literal), por lo que se usaba la sintaxis normal del constructor, por ejemplo:
std::string str = "initializer syntax";
std::string str("converting constructor syntax");
std::string str = string("explicit constructor syntax");
Todas ellas tienen la misma interpretación. Desde C++11, también hay una nueva sintaxis de constructor:
std::string str{"uniform initializer syntax"};
auto str = "constexpr literal syntax"s;
Al utilizar comillas, si se desea representar el delimitador en sí en un literal de cadena, se produce el problema de la colisión de delimitadores . Por ejemplo, si el delimitador es una comilla doble, no se puede representar simplemente una comilla doble en sí misma mediante el literal, """
ya que la segunda comilla se interpreta como el final del literal de cadena, no como el valor de la cadena, y de manera similar, no se puede escribir, "This is "in quotes", but invalid."
ya que la parte intermedia entre comillas se interpreta como fuera de las comillas. Existen varias soluciones, la más general de las cuales es utilizar secuencias de escape, como "\""
o "This is \"in quotes\" and properly escaped."
, pero hay muchas otras soluciones.
Las comillas emparejadas, como las llaves en Tcl, permiten cadenas anidadas, como {foo {bar} zork}
pero no resuelven el problema de la colisión de delimitadores, ya que un delimitador de cierre desequilibrado no se puede incluir simplemente, como en {}}
.
Varios lenguajes, incluidos Pascal , BASIC , DCL , Smalltalk , SQL , J y Fortran , evitan la colisión de delimitadores duplicando las comillas que pretenden ser parte del literal de cadena en sí:
'Esta cadena Pascal '' contiene dos apóstrofos ' '
Dije: "¿Puedes oírme?"
Algunos lenguajes, como Fortran , Modula-2 , JavaScript , Python y PHP permiten más de un delimitador de comillas; en el caso de dos delimitadores posibles, esto se conoce como comillas duales . Por lo general, esto consiste en permitir que el programador use comillas simples o comillas dobles indistintamente: cada literal debe usar una u otra.
"Esta es la manzana de Juan". Dije: "¿Puedes oírme?"
Sin embargo, esto no permite tener un único literal con ambos delimitadores. Esto se puede solucionar utilizando varios literales y concatenando cadenas :
Dije: "Esto es ' + 'John' + 'manzana"."
Python tiene concatenación de literales de cadena , por lo que los literales de cadena consecutivos se concatenan incluso sin un operador, por lo que esto se puede reducir a:
Dije: "Esta es la manzana de 'John' ".
C++11 introdujo los llamados literales de cadena sin formato . Consisten, esencialmente, en
R"
(
contenido de id de fin de cadena )
id de fin de cadena "
,es decir, después de que R"
el programador puede ingresar hasta 16 caracteres excepto caracteres de espacio en blanco, paréntesis o barra invertida, que forman el id de fin de cadena (su propósito es repetirse para señalar el final de la cadena, id eos para abreviar), entonces se requiere un paréntesis de apertura (para indicar el final del id eos). Luego sigue el contenido real del literal: Se puede usar cualquier carácter de secuencia (excepto que no puede contener un paréntesis de cierre seguido del id eos seguido de una comilla), y finalmente, para terminar la cadena, se requiere un paréntesis de cierre, el id eos y una comilla.
El caso más simple de un literal de este tipo es con contenido vacío y id eos vacío: R"()"
.
El id eos puede contener comillas: R""(I asked, "Can you hear me?")""
es un literal válido (el id eos está "
aquí).
Las secuencias de escape no funcionan en literales de cadena sin formato.
D admite algunos delimitadores entre comillas, con cadenas que comienzan con q"
más un delimitador de apertura y terminan con el delimitador de cierre respectivo y "
. Los pares de delimitadores disponibles son ()
, <>
, {}
y []
; un delimitador no identificador no emparejado es su propio delimitador de cierre. Los delimitadores emparejados se anidan, por lo que es un literal válido; un ejemplo con el carácter q"(A pair "()" of parens in quotes)"
no anidado es .
De manera similar a C++11, D permite literales de estilo aquí-documento con identificadores de fin de cadena:/
q"/I asked, "Can you hear me?"/"
q"
id de fin de cadena contenido de nueva línea id de fin de cadena "
En D, el id de final de cadena debe ser un identificador (caracteres alfanuméricos).
En algunos lenguajes de programación, como sh y Perl , hay diferentes delimitadores que se tratan de manera diferente, como por ejemplo, si se realiza interpolación de cadenas o no, y por lo tanto se debe tener cuidado al elegir qué delimitador utilizar; consulte los diferentes tipos de cadenas a continuación.
Una extensión adicional es el uso de comillas múltiples , que permite al autor elegir qué caracteres deben especificar los límites de un literal de cadena.
Por ejemplo, en Perl :
qq^Dije, "¿Puedes oírme?"^ qq@Dije, "¿Puedes oírme?"@ qq§Dije, "¿Puedes oírme?"§
Todas producen el resultado deseado. Aunque esta notación es más flexible, pocos lenguajes la admiten; además de Perl, Ruby (influenciado por Perl) y C++11 también las admiten. Una variante de las comillas múltiples es el uso de cadenas de estilo document here .
Lua (a partir de la versión 5.1) ofrece una forma limitada de comillas múltiples, en particular para permitir la anidación de comentarios largos o cadenas incrustadas. Normalmente, se utilizan [[
y ]]
para delimitar cadenas literales (se elimina el salto de línea inicial, de lo contrario se conservan sin formato), pero los corchetes de apertura pueden incluir cualquier número de signos de igual, y solo los corchetes de cierre con el mismo número de signos cierran la cadena. Por ejemplo:
local ls = [=[ Esta notación se puede utilizar para rutas de Windows: ruta local = [[C:\Windows\Fonts]] ]=]
El uso de comillas múltiples es particularmente útil con expresiones regulares que contienen delimitadores habituales, como comillas, ya que esto evita la necesidad de escaparlas. Un ejemplo temprano es sed , donde en el comando de sustitución los delimitadores de barra predeterminados se pueden reemplazar por otro carácter, como en .s/regex/replacement/
/
s,regex,replacement,
Otra opción, que rara vez se utiliza en los lenguajes modernos, es utilizar una función para construir una cadena, en lugar de representarla mediante un literal. Esto no suele utilizarse en los lenguajes modernos porque el cálculo se realiza en tiempo de ejecución, en lugar de en tiempo de análisis.
Por ejemplo, las primeras formas de BASIC no incluían secuencias de escape ni ninguna de las otras soluciones alternativas enumeradas aquí, y por lo tanto, se requería utilizar la CHR$
función, que devuelve una cadena que contiene el carácter correspondiente a su argumento. En ASCII, las comillas tienen el valor 34, por lo que para representar una cadena con comillas en un sistema ASCII se escribiría
"Dije, " + CHR$ ( 34 ) + "¿Puedes oírme?" + CHR$ ( 34 )
En C, hay una función similar disponible a través sprintf
del %c
especificador de formato "carácter", aunque en presencia de otras soluciones alternativas generalmente no se utiliza:
char buffer [ 32 ]; snprintf ( buffer , tamaño del buffer , "Esto es %cin comillas.%c" , 34 , 34 );
Estas funciones constructoras también se pueden utilizar para representar caracteres no imprimibles, aunque generalmente se utilizan secuencias de escape. Se puede utilizar una técnica similar en C++ con el std::string
operador de conversión en cadenas.
Las secuencias de escape son una técnica general para representar caracteres que de otra manera serían difíciles de representar directamente, incluidos los delimitadores, caracteres no imprimibles (como los retrocesos), las nuevas líneas y los caracteres de espacio en blanco (que de otra manera son imposibles de distinguir visualmente), y tienen una larga historia. Por lo tanto, se usan ampliamente en literales de cadena, y agregar una secuencia de escape (ya sea a un solo carácter o a lo largo de una cadena) se conoce como escape .
Se elige un carácter como prefijo para codificar caracteres que son difíciles o imposibles de incluir directamente. El más común es la barra invertida ; además de otros caracteres, un punto clave es que la barra invertida en sí misma puede codificarse como una barra invertida doble \\
y, para cadenas delimitadas, el delimitador en sí mismo puede codificarse mediante un escape, por ejemplo, \"
para ". Se puede dar una expresión regular para dichas cadenas con escape de la siguiente manera, como se encuentra en la especificación ANSI C : [1] [a]
"(\\.|[^\\"])*"
que significa "una comilla; seguida de cero o más caracteres de escape (barra invertida seguida de algo, posiblemente barra invertida o comilla), o un carácter que no sea de escape ni de comilla; que termina en comilla"; el único problema es distinguir la comilla final de una comilla precedida por una barra invertida, que puede ser de escape. Pueden aparecer varios caracteres después de la barra invertida, como \uFFFF
, según el esquema de escape.
Luego, es necesario analizar léxicamente una cadena escapada , convirtiendo la cadena escapada en la cadena no escapada que representa. Esto se hace durante la fase de evaluación del análisis léxico general del lenguaje de programación: el evaluador del analizador léxico del lenguaje general ejecuta su propio analizador léxico para literales de cadena escapados.
Entre otras cosas, debe ser posible codificar el carácter que normalmente termina la constante de cadena, además de que debe haber alguna forma de especificar el carácter de escape en sí. Las secuencias de escape no siempre son bonitas o fáciles de usar, por lo que muchos compiladores también ofrecen otros medios para resolver los problemas comunes. Sin embargo, las secuencias de escape resuelven todos los problemas de delimitadores y la mayoría de los compiladores interpretan las secuencias de escape. Cuando un carácter de escape está dentro de un literal de cadena, significa "este es el comienzo de la secuencia de escape". Cada secuencia de escape especifica un carácter que se colocará directamente en la cadena. El número real de caracteres necesarios en una secuencia de escape varía. El carácter de escape está en la parte superior/izquierda del teclado, pero el editor lo traducirá, por lo tanto, no se puede grabar directamente en una cadena. La barra invertida se utiliza para representar el carácter de escape en un literal de cadena.
Muchos lenguajes admiten el uso de metacaracteres dentro de cadenas literales. Los metacaracteres tienen distintas interpretaciones según el contexto y el lenguaje, pero generalmente son una especie de "comando de procesamiento" para representar caracteres imprimibles o no imprimibles.
Por ejemplo, en un literal de cadena de caracteres C , si la barra invertida va seguida de una letra como "b", "n" o "t", entonces esto representa un carácter de retroceso , de nueva línea o de tabulación no imprimible , respectivamente. O si la barra invertida va seguida de 1 a 3 dígitos octales , entonces esta secuencia se interpreta como la representación de la unidad de código arbitraria con el valor especificado en la codificación del literal (por ejemplo, el código ASCII correspondiente para un literal ASCII). Esto se amplió posteriormente para permitir una notación de código de caracteres hexadecimal más moderna :
"Dije, ¿ me escuchas? "
Secuencia de escape | Unicode | Caracteres literales colocados en una cadena |
---|---|---|
\0 | U+0000 | carácter nulo [2] [3] (normalmente como un caso especial de notación octal \ooo) |
\a | U+0007 | alerta [4] [5] |
\b | U+0008 | retroceso [4] |
\F | U+000C | avance de página [4] |
\norte | U+000A | salto de línea [4] (o nueva línea en POSIX) |
\r | U+000D | retorno de carro [4] (o nueva línea en Mac OS 9 y anteriores) |
\t | U+0009 | pestaña horizontal [4] |
\v | U+000B | pestaña vertical [4] |
\mi | U+001B | carácter de escape [5] ( GCC , [6] clang y tcc ) |
\u#### | Tú+#### | Carácter Unicode de 16 bits donde #### son cuatro dígitos hexadecimales [3] |
\U######## | Tú+###### | Carácter Unicode de 32 bits donde ######## son ocho dígitos hexadecimales (el espacio de caracteres Unicode actualmente tiene solo 21 bits de ancho, por lo que los dos primeros dígitos hexadecimales siempre serán cero) |
\u{######} | Tú+###### | Carácter Unicode de 21 bits donde ###### es un número variable de dígitos hexadecimales |
\incógnita## | Depende de la codificación [b] | Especificación de caracteres de 8 bits donde # es un dígito hexadecimal. La longitud de una secuencia de escape hexadecimal no está limitada a dos dígitos, sino que tiene una longitud arbitraria. [4] |
\ooo | Depende de la codificación [b] | Especificación de caracteres de 8 bits donde o es un dígito octal [4] |
" " | U+0022 | comillas dobles (") [4] |
\& | carácter no característico utilizado para delimitar escapes numéricos en Haskell [2] | |
" ' | U+0027 | comilla simple (') [4] |
\\ | U+005C | barra invertida (\) [4] |
\? | U+003F | signo de interrogación (?) [4] |
Nota: No todos los analizadores admiten todas las secuencias de la lista y puede haber otras secuencias de escape que no estén en la lista.
Cuando el código de un lenguaje de programación se incrusta dentro de otro, las cadenas incrustadas pueden requerir múltiples niveles de escape. Esto es particularmente común en expresiones regulares y consultas SQL dentro de otros lenguajes, o en otros lenguajes dentro de scripts de shell. Este doble escape suele ser difícil de leer y crear.
El uso incorrecto de comillas en cadenas anidadas puede presentar una vulnerabilidad de seguridad. El uso de datos no confiables, como en los campos de datos de una consulta SQL, debe utilizar sentencias preparadas para evitar un ataque de inyección de código . En PHP 2 a 5.3, había una función llamada comillas mágicas que escapaba automáticamente las cadenas (por conveniencia y seguridad), pero debido a problemas se eliminó a partir de la versión 5.4.
Algunos lenguajes proporcionan un método para especificar que un literal se debe procesar sin ninguna interpretación específica del lenguaje. Esto evita la necesidad de escapes y produce cadenas más legibles.
Las cadenas sin formato son particularmente útiles cuando se necesita escapar un carácter común, en particular en expresiones regulares (anidadas como literales de cadena), donde la barra invertida \
se usa ampliamente, y en rutas de DOS/Windows , donde la barra invertida se usa como separador de ruta. La profusión de barras invertidas se conoce como síndrome del palillo inclinado y se puede reducir mediante el uso de cadenas sin formato. Compare los nombres de ruta sin formato y con escape en C#:
"La ruta de Windows es C:\\Foo\\Bar\\Baz\\" @"La ruta de Windows es C:\Foo\Bar\Baz\"
Los ejemplos extremos se dan cuando se combinan: las rutas de la Convención de nomenclatura uniforme comienzan con \\
, y, por lo tanto, una expresión regular con escape que coincida con un nombre UNC comienza con 8 barras invertidas, "\\\\\\\\"
, debido a la necesidad de escapar la cadena y la expresión regular. El uso de cadenas sin formato reduce esto a 4 (escape en la expresión regular), como en C# @"\\\\"
.
En los documentos XML, las secciones CDATA permiten el uso de caracteres como & y < sin que un analizador XML intente interpretarlos como parte de la estructura del documento en sí. Esto puede resultar útil cuando se incluye texto literal y código de script, para mantener el documento bien formado .
<![CDATA[ if (ruta!=null && profundidad<2) { add(ruta); } ]]>
En muchos lenguajes, los literales de cadena pueden contener saltos de línea literales que abarcan varias líneas. Alternativamente, los saltos de línea pueden tener caracteres de escape, generalmente como \n
. Por ejemplo:
eco 'foo bar'
y
echo -e "foo\nbar"
Ambos son bash válidos y producen:
comidabar
Entre los lenguajes que permiten saltos de línea literales se incluyen bash, Lua, Perl, PHP, R y Tcl. En otros lenguajes, los literales de cadena no pueden incluir saltos de línea.
Dos problemas con los literales de cadena de varias líneas son las nuevas líneas iniciales y finales y la sangría. Si los delimitadores inicial o final están en líneas separadas, hay nuevas líneas adicionales, mientras que si no lo están, el delimitador hace que la cadena sea más difícil de leer, en particular en el caso de la primera línea, que a menudo tiene una sangría diferente al resto. Además, el literal no debe tener sangría, ya que se conservan los espacios en blanco iniciales; esto interrumpe el flujo del código si el literal aparece dentro de un código con sangría.
La solución más común para estos problemas son los literales de cadena de estilo here document . Formalmente hablando, un here document no es un literal de cadena, sino un literal de flujo o literal de archivo. Estos se originan en scripts de shell y permiten que un literal se introduzca como entrada a un comando externo. El delimitador de apertura es <<END
where END
puede ser cualquier palabra, y el delimitador de cierre está END
en una línea por sí mismo, sirviendo como un límite de contenido; esto <<
se debe a la redirección de stdin desde el literal. Debido a que el delimitador es arbitrario, estos también evitan el problema de la colisión de delimitadores. Estos también permiten que las tabulaciones iniciales se eliminen a través de la sintaxis variante <<-END
, aunque los espacios iniciales no se eliminan. Desde entonces, se ha adoptado la misma sintaxis para literales de cadena de varias líneas en varios lenguajes, más notablemente Perl, y también se conocen como here documents, y conservan la sintaxis, a pesar de ser cadenas y no involucrar redirección. Al igual que con otros literales de cadena, a veces se les puede especificar un comportamiento diferente, como la interpolación de variables.
Python, cuyos literales de cadena habituales no permiten saltos de línea literales, tiene en cambio una forma especial de cadena, diseñada para literales de varias líneas, llamada comillas triples . Estas utilizan un delimitador triple, ya sea '''
o """
. Estos literales se utilizan especialmente para la documentación en línea, conocida como docstrings .
Tcl permite nuevas líneas literales en cadenas y no tiene una sintaxis especial para ayudar con cadenas de varias líneas, aunque los delimitadores se pueden colocar en las líneas por sí solos y las nuevas líneas iniciales y finales se pueden eliminar mediante string trim
, mientras que string map
se puede usar para eliminar la sangría.
Algunos lenguajes proporcionan concatenación de literales de cadena , donde los literales de cadena adyacentes se unen implícitamente en un solo literal en tiempo de compilación. Esta es una característica de C, [7] [8] C++, [9] D, [10] Ruby, [11] y Python, [12] que la copió de C. [13] En particular, esta concatenación ocurre en tiempo de compilación, durante el análisis léxico (como una fase posterior a la tokenización inicial), y contrasta tanto con la concatenación de cadenas en tiempo de ejecución (generalmente con el +
operador) [14] como con la concatenación durante el plegado constante , que ocurre en tiempo de compilación, pero en una fase posterior (después del análisis de frases o "parsing"). La mayoría de los lenguajes, como C#, Java [15] y Perl, no admiten la concatenación implícita de literales de cadena y, en su lugar, requieren una concatenación explícita, como con el +
operador (esto también es posible en D y Python, pero ilegal en C/C++; consulte a continuación); En este caso, la concatenación puede ocurrir en tiempo de compilación, a través del plegado constante, o puede diferirse hasta el tiempo de ejecución.
En C, donde se originan el concepto y el término, la concatenación de literales de cadena se introdujo por dos razones: [16]
En términos prácticos, esto permite la concatenación de cadenas en las primeras fases de la compilación ("traducción", específicamente como parte del análisis léxico), sin necesidad de análisis de frases ni plegado de constantes. Por ejemplo, los siguientes son válidos en C/C++:
char * s = "hola, " "mundo" ; printf ( "hola, " "mundo" );
Sin embargo, lo siguiente no es válido:
char * s = "hola, " + "mundo" ; printf ( "hola, " + "mundo" );
Esto se debe a que los literales de cadena tienen un tipo de matriz , (C) o (C++), que no se puede agregar; esto no es una restricción en la mayoría de los otros lenguajes.char [n]
const char [n]
Esto es particularmente importante cuando se utiliza en combinación con el preprocesador C , para permitir que las cadenas se calculen después del preprocesamiento, particularmente en macros. [13] Como ejemplo simple:
char * archivo_y_mensaje = __ARCHIVO__ ": mensaje" ;
se expandirá (si el archivo se llama ac) a:
char * archivo_y_mensaje = "ac" ": mensaje" ;
que luego se concatena, siendo equivalente a:
char * archivo_y_mensaje = "ac: mensaje" ;
Un caso de uso común es la construcción de cadenas de formato printf o scanf, donde los especificadores de formato se dan mediante macros. [18] [19]
Un ejemplo más complejo utiliza la conversión de números enteros en cadenas (por parte del preprocesador) para definir una macro que se expande a una secuencia de literales de cadena, que luego se concatenan en un único literal de cadena con el nombre del archivo y el número de línea: [20]
#define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) #define EN __ARCHIVO__ ": TOSTRING(__LÍNEA__)
Más allá de los requisitos sintácticos de C/C++, la concatenación implícita es una forma de azúcar sintáctica que simplifica la división de cadenas literales en varias líneas, evitando la necesidad de continuar líneas (mediante barras invertidas) y permitiendo agregar comentarios a partes de las cadenas. Por ejemplo, en Python, se puede comentar una expresión regular de esta manera: [21]
re . compile ( "[A-Za-z_]" # letra o guión bajo "[A-Za-z0-9_]*" # letra, dígito o guión bajo )
Los compiladores modernos no requieren la concatenación implícita de cadenas, ya que implementan un plegado constante y provocan errores difíciles de detectar debido a una concatenación involuntaria al omitir una coma, particularmente en listas verticales de cadenas, como en:
l = [ 'foo' , 'bar' 'zork' ]
En consecuencia, no se utiliza en la mayoría de los lenguajes, y se ha propuesto su desaprobación en D [22] y Python. [13] Sin embargo, eliminar la característica rompe la compatibilidad con versiones anteriores, y reemplazarla con un operador de concatenación introduce problemas de precedencia: la concatenación de literales de cadena ocurre durante el análisis léxico, antes de la evaluación del operador, pero la concatenación a través de un operador explícito ocurre al mismo tiempo que otros operadores, por lo tanto, la precedencia es un problema, que potencialmente requiere paréntesis para asegurar el orden de evaluación deseado.
Un problema más sutil es que en C y C++, [23] hay diferentes tipos de literales de cadena, y la concatenación de estos tiene un comportamiento definido por la implementación, lo que plantea un riesgo de seguridad potencial. [24]
Algunos lenguajes proporcionan más de un tipo de literal, que tienen un comportamiento diferente. Esto se usa particularmente para indicar cadenas sin formato (sin escape) o para habilitar o deshabilitar la interpolación de variables, pero tiene otros usos, como distinguir conjuntos de caracteres. La mayoría de las veces, esto se hace cambiando el carácter de comillas o agregando un prefijo o sufijo. Esto es comparable a los prefijos y sufijos de los literales enteros , como para indicar números hexadecimales o enteros largos.
Uno de los ejemplos más antiguos se encuentra en los scripts de shell, donde las comillas simples indican una cadena sin formato o "cadena literal", mientras que las comillas dobles indican secuencias de escape e interpolación de variables.
Por ejemplo, en Python , las cadenas sin formato están precedidas por un r
o R
– compare 'C:\\Windows'
con r'C:\Windows'
(aunque, una cadena sin formato de Python no puede terminar en un número impar de barras invertidas). Python 2 también distingue dos tipos de cadenas: cadenas ASCII de 8 bits ("bytes") (el valor predeterminado), indicadas explícitamente con un prefijo b
o B
, y cadenas Unicode, indicadas con un prefijo u
o U
. [25] mientras que en Python 3 las cadenas son Unicode por defecto y los bytes son un tipo separado bytes
que cuando se inicializa con comillas debe tener como prefijo un b
.
La notación de C# para cadenas sin formato se llama @-quoting.
@"C:\Foo\Bar\Baz\"
Si bien esto deshabilita el escape, permite comillas dobles, que permiten representar comillas dentro de la cadena:
@"Dije, "Hola.""
C++11 permite cadenas sin formato, cadenas Unicode (UTF-8, UTF-16 y UTF-32) y cadenas de caracteres anchos, determinadas por prefijos. También agrega literales para el C++ existente string
, que generalmente se prefiere a las cadenas de estilo C existentes.
En Tcl, las cadenas delimitadas por llaves son literales, mientras que las cadenas delimitadas por comillas tienen escape e interpolación.
Perl tiene una amplia variedad de cadenas, que formalmente se consideran operadores y se conocen como operadores de comillas y similares . Estos incluyen tanto una sintaxis habitual (delimitadores fijos) como una sintaxis genérica, que permite una selección de delimitadores; estas incluyen: [26]
'' "" `` // m// qr// s/// y // / q{} qq{} qx{} qw{} m{} qr{} s{}{} tr {}{} y {}{}
REXX utiliza caracteres de sufijo para especificar caracteres o cadenas utilizando su código hexadecimal o binario. Por ejemplo,
'20' x "0010 0000" b "00100000" b
todos producen el carácter de espacio , evitando la llamada a la función X2C(20)
.
En algunos lenguajes, los literales de cadena pueden contener marcadores de posición que hacen referencia a variables o expresiones en el contexto actual , que se evalúan (normalmente en tiempo de ejecución). Esto se conoce como interpolación de variables o, de forma más general, interpolación de cadenas . Los lenguajes que admiten la interpolación suelen distinguir los literales de cadena que se interpolan de los que no. Por ejemplo, en los shells de Unix compatibles con sh (así como en Perl y Ruby), las cadenas entre comillas dobles (delimitadas por comillas, ") se interpolan, mientras que las cadenas entre comillas simples (delimitadas por apóstrofos, ') no. Los literales de cadena no interpolados a veces se denominan "cadenas sin formato", pero esto es distinto de "cadena sin formato" en el sentido de escape. Por ejemplo, en Python, una cadena prefijada con r
o R
no tiene escape ni interpolación, una cadena normal (sin prefijo) tiene escape pero no interpolación, y una cadena prefijada con f
o F
tiene escape e interpolación.
Por ejemplo, el siguiente código Perl :
$name = "Nancy" ; $greeting = "Hola mundo" ; print "$name dijo $greeting a la multitud de personas." ;
produce la salida:
Nancy dijo Hola Mundo a la multitud de personas.
En este caso, el metacarácter ($) (que no debe confundirse con el sigilo en la declaración de asignación de variable) se interpreta para indicar interpolación de variable y requiere algún tipo de escape si necesita imprimirse literalmente.
Esto debe contrastarse con la printf
función, que produce el mismo resultado utilizando una notación como:
printf "%s dijo %s a la multitud de personas." , $nombre , $saludo ;
pero no realiza interpolación: %s
es un marcador de posición en una cadena de formato printf , pero las variables en sí están fuera de la cadena.
Esto contrasta con las cadenas "sin procesar":
imprimir '$nombre dijo $saludo a la multitud de personas.' ;
que producen resultados como:
$name dijo $saludo a la multitud de personas.
Aquí los caracteres $ no son metacaracteres y no se interpretan como si tuvieran ningún significado más allá del texto simple.
Los lenguajes que carecen de flexibilidad para especificar cadenas literales hacen que sea especialmente complicado escribir código de programación que genere otro código de programación. Esto es particularmente cierto cuando el lenguaje de generación es el mismo o similar al lenguaje de salida.
Por ejemplo:
Sin embargo, algunos lenguajes están particularmente bien adaptados para producir este tipo de salida autosimilar, especialmente aquellos que admiten múltiples opciones para evitar la colisión de delimitadores.
El uso de cadenas literales como código que genera otro código puede tener consecuencias adversas para la seguridad, especialmente si el resultado se basa, al menos parcialmente, en datos ingresados por el usuario que no son de confianza. Esto es particularmente grave en el caso de las aplicaciones basadas en la Web, donde los usuarios malintencionados pueden aprovechar dichas debilidades para subvertir el funcionamiento de la aplicación, por ejemplo, organizando un ataque de inyección SQL .