Un literal de cadena o cadena anónima [1] es un tipo de literal en programación para la representación de un valor de cadena dentro del código fuente de un programa de computadora . La mayoría de las veces, en los lenguajes modernos, se trata de una secuencia de caracteres entre comillas (formalmente " delimitadores entre corchetes "), como en x = "foo"
, donde "foo"
es una cadena literal con valor foo
: las comillas no forman parte del valor y se debe utilizar un método como las secuencias de escape. para evitar el problema de la colisión de delimitadores y permitir que los delimitadoresellos mismos para estar incrustados en una cuerda. Sin embargo, existen numerosas notaciones alternativas para especificar cadenas literales, particularmente casos más complicados, y la notación exacta depende del lenguaje de programación individual en cuestión. Sin embargo, existen algunas pautas generales que siguen la mayoría de los lenguajes de programación modernos.
Sintaxis
Delimitadores entre corchetes
La mayoría de los lenguajes de programación modernos usan delimitadores de corchetes (también delimitadores balanceados ) para especificar cadenas literales. Las comillas dobles son los delimitadores de comillas más utilizados:
"¡Hola!"
Una cadena vacía está literalmente escrita por un par de comillas sin ningún carácter en el medio:
""
Algunos idiomas permiten o exigen el uso de comillas simples en lugar de dobles (la cadena debe comenzar y terminar con el mismo tipo de comillas y el tipo de comillas puede o no dar una semántica ligeramente diferente):
'¡Hola!'
Estas comillas no están emparejadas (el mismo carácter se usa como abridor y cerrador), lo cual es una resaca de la tecnología de la máquina de escribir que fue la precursora de los primeros dispositivos de entrada y salida de computadora.
En términos de expresiones regulares , un literal de cadena entre comillas básico se da como:
"[^"] * "
Esto significa que un literal de cadena se escribe como: una comilla, seguida de cero, uno o más caracteres que no sean comillas, seguidos de una comilla . En la práctica, esto a menudo se complica al escapar, otros delimitadores y excluir nuevas líneas.
Delimitadores emparejados
Varios idiomas proporcionan delimitadores emparejados, donde los delimitadores de apertura y cierre son diferentes. Estos también suelen permitir cadenas anidadas, por lo que los delimitadores se pueden incrustar, siempre que estén emparejados, pero aún así dan como resultado una colisión de delimitadores para incrustar un delimitador de cierre no emparejado. Los ejemplos incluyen PostScript , que usa paréntesis, como en (The quick (brown fox))
y m4 , que usa la comilla invertida (`) como delimitador inicial y el apóstrofo (') como delimitador final. Tcl permite tanto comillas (para cadenas interpoladas) como llaves (para cadenas sin formato), como en "The quick brown fox"
o {The quick {brown fox}}
; esto se deriva de las comillas simples en los shells de Unix y el uso de llaves en C para declaraciones compuestas, ya que los bloques de código en Tcl son sintácticamente lo mismo que los literales de cadena; que los delimitadores estén emparejados es esencial para hacer esto factible.
Si bien el conjunto de caracteres Unicode incluye versiones emparejadas (apertura y cierre por separado) de comillas simples y dobles, utilizadas en texto, principalmente en otros idiomas además del inglés, rara vez se usan en lenguajes de programación (porque se prefiere ASCII y no se incluyen en ASCII):
"¡Hola!" '¡Hola!' "¡Hola!" "¡Hola!"
Las citas dobles emparejadas se pueden utilizar en Visual Basic .NET , pero muchos otros lenguajes de programación no las aceptan. Se prefieren las marcas no emparejadas por compatibilidad, ya que son más fáciles de escribir en una amplia gama de teclados y, por lo tanto, incluso en los idiomas en los que están permitidas, muchos proyectos prohíben su uso para el código fuente.
Delimitadores de espacios en blanco
Los literales de cadena pueden terminar con líneas nuevas.
Un ejemplo son los parámetros de la plantilla de MediaWiki .
{{Navbox | nombre = Nulos | title = [[wikt: Null | Nulls]] en [[informática]] }}
Puede haber una sintaxis especial para cadenas de varias líneas.
En YAML , los literales de cadena se pueden especificar mediante el posicionamiento relativo de los espacios en blanco y la sangría.
- título : Un ejemplo de cadena de varias líneas en el cuerpo YAML : | Esta es una cadena de varias líneas. Aquí pueden aparecer metacaracteres "especiales" . La extensión de esta cadena está representada por sangría.
Sin delimitadores
Algunos lenguajes de programación, como Perl, JavaScript y PHP, permiten cadenas literales sin delimitadores en algunos contextos. En los siguientes programas en Perl y JavaScript, por ejemplo, red
, green
, y blue
son literales de cadena, pero son sin comillas:
% mapa = ( rojo => 0x00f , azul => 0x0f0 , verde => 0xf00 );
mapa = { 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 siguientes dos líneas de Perl son equivalentes:
$ y = "x" ; $ y = x ;
Notación declarativa
En el lenguaje de programación FORTRAN original (por ejemplo), los literales de cadena se escribían en la denominada notación Hollerith , donde un recuento decimal del número de caracteres iba seguido de la letra H, y luego los caracteres de la cadena:
35 HAn ejemplo literal de cadena de Hollerith
Este estilo de notación declarativa se contrasta con las comillas delimitador entre corchetes , porque no requiere el uso de caracteres "entre corchetes" equilibrados en ninguno de los lados de la cadena.
Ventajas:
- elimina la búsqueda de texto (para el carácter delimitador) y, por lo tanto, requiere una sobrecarga significativamente menor
- evita el problema de la colisión del delimitador
- permite la inclusión de metacaracteres que de otro modo podrían confundirse con comandos
- se puede utilizar para una compresión de datos bastante eficaz de cadenas de texto sin formato [ cita requerida ]
Inconvenientes:
- este tipo de notación es propenso a errores si se utiliza como la entrada manual por programadores
- Se necesita especial cuidado en caso de codificaciones multibyte.
Sin embargo, esto no es un inconveniente cuando el prefijo es generado por un algoritmo, como es muy probable que sea el caso. [ cita requerida ]
Funciones de constructor
C ++ tiene dos estilos de cadena, uno heredado de C (delimitado por "
) y el más seguro std::string
en la biblioteca estándar de C ++. La std::string
clase se usa con frecuencia de la misma manera que se usaría un literal de cadena en otros idiomas, y a menudo se prefiere a las cadenas de estilo C por su mayor flexibilidad y seguridad. Pero viene con una penalización de rendimiento para los literales de cadena, ya que std::string
generalmente asigna memoria dinámicamente y debe copiarle el literal de cadena de estilo C en tiempo de ejecución.
Antes de C ++ 11, no había literal para cadenas de C ++ (C ++ 11 permite "this is a C++ string"s
con el s
al final del literal), por lo que se usó la sintaxis de constructor normal, por ejemplo:
std::string str = "initializer syntax";
std::string str("converting constructor syntax");
std::string str = string("explicit constructor syntax");
todos los cuales 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;
Colisión de delimitadores
Cuando se utilizan comillas, si se desea representar el delimitador en sí mismo en un literal de cadena, se encuentra el problema de la colisión del delimitador . Por ejemplo, si el delimitador es una comilla doble, uno no puede simplemente representar una comilla doble por el literal """
ya que la segunda cita 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."
como la parte intermedia entre comillas se interpreta en cambio como fuera de las comillas. Existen varias soluciones, la más general de las cuales es usar 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 del delimitador, ya que un delimitador de cierre no equilibrado no se puede incluir simplemente, como en {}}
.
Doblar
Varios lenguajes, incluidos Pascal , BASIC , DCL , Smalltalk , SQL , J y Fortran , evitan la colisión de delimitadores al duplicar las comillas que están destinadas a ser parte de la cadena literal en sí:
'Esta cadena de Pascal ' ' contiene dos apóstrofos ' ' '
"Dije," "¿Puedes oírme?" ""
Cotización dual
Algunos lenguajes, como Fortran , Modula-2 , JavaScript , Python y PHP permiten más de un delimitador de comillas; en el caso de dos posibles delimitadores, esto se conoce como comillas dobles . Por lo general, esto consiste en permitir que el programador use comillas simples o dobles de manera intercambiable; cada literal debe usar una u otra.
"Esta es la manzana de John". 'Dije: "¿Puedes oírme?"
Sin embargo, esto no permite tener un solo literal con ambos delimitadores. Esto se puede solucionar usando varios literales y usando la concatenación de cadenas :
'Dije:' Esta es ' + ' John's ' + ' apple ''.
Python tiene una concatenación literal de cadena , por lo que las cadenas literales consecutivas se concatenan incluso sin un operador, por lo que esto se puede reducir a:
Dije: "Esta es la" manzana de John " .
D admite algunos delimitadores de comillas, con tales cadenas que comienzan q"[
y terminan con ]"
o de manera similar para otro carácter delimitador (cualquiera de () <> {} o []). D también admite aquí cadenas de estilo de documento a través de una sintaxis similar.
En algunos lenguajes de programación, como sh y Perl , existen diferentes delimitadores que se tratan de manera diferente, como hacer interpolación de cadenas o no, por lo que se debe tener cuidado al elegir qué delimitador usar; vea diferentes tipos de cadenas , a continuación.
Cotización múltiple
Una extensión adicional es el uso de comillas múltiples , que le permite al autor elegir qué caracteres deben especificar los límites de una cadena literal.
Por ejemplo, en Perl :
qq ^ Dije: "¿Puedes oírme?" ^ qq @ Dije: "¿Puedes oírme?" @ qq§ Dije: "¿Puedes oírme?" §
todos producen el resultado deseado. Aunque esta notación es más flexible, pocos idiomas la admiten; además de Perl, Ruby (influenciado por Perl) y C ++ 11 también los admiten. En C ++ 11, las cadenas sin formato pueden tener varios delimitadores, que comienzan con R"delimiter(
y terminan con )delimiter"
. El delimitador puede tener una longitud de cero a 16 caracteres y puede contener cualquier miembro del conjunto de caracteres de origen básico, excepto espacios en blanco, paréntesis o barra invertida. Una variante de las citas múltiples es el uso de cadenas de estilo de documento aquí .
Lua (a partir de 5.1) proporciona una forma limitada de comillas múltiples, particularmente para permitir el anidamiento de comentarios largos o cadenas incrustadas. Normalmente se usa [[
y ]]
para delimitar cadenas literales (nueva línea inicial despojada, de lo contrario sin formato), pero los corchetes de apertura pueden incluir cualquier número de signos iguales, 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]] ] =]
Las comillas múltiples son particularmente útiles con expresiones regulares que contienen delimitadores habituales, como comillas, ya que esto evita la necesidad de escapar de ellas. Un ejemplo temprano es sed , donde en el comando de sustitución los delimitadores de barra inclinados predeterminados se pueden reemplazar por otro carácter, como en .s/regex/replacement/
/
s,regex,replacement,
Funciones de constructor
Otra opción, que rara vez se usa en los lenguajes modernos, es usar una función para construir una cadena, en lugar de representarla mediante un literal. Por lo general, esto no se usa 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 otra solución alternativa enumerada aquí y, por lo tanto, se requería una para usar 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, una función similar está disponible a través sprintf
del %c
especificador de formato "carácter", aunque en presencia de otras soluciones, esto generalmente no se usa:
sprintf ( "Esto es% cin comillas.% c" , 34 , 34 );
Estas funciones constructoras también se pueden usar para representar caracteres no imprimibles, aunque generalmente se usan secuencias de escape. Se puede utilizar una técnica similar en C ++ con el std::string
operador de cadena.
Secuencias de escape
Las secuencias de escape son una técnica general para representar caracteres que de otro modo serían difíciles de representar directamente, incluidos delimitadores, caracteres no imprimibles (como retrocesos), nuevas líneas y caracteres de espacios en blanco (que de otro modo serían imposibles de distinguir visualmente), y tienen una larga historia. Por lo tanto, se utilizan 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 dar codificaciones a los caracteres que son difíciles o imposibles de incluir directamente. Lo más común es que se trate de una barra invertida ; Además de otros caracteres, un punto clave es que la barra invertida en sí misma se puede codificar como una barra invertida doble \\
y, para las cadenas delimitadas, el delimitador en sí se puede codificar escapando, por ejemplo, \"
para ". Una expresión regular para tales cadenas de escape se puede dar de la siguiente manera , como se encuentra en la especificación ANSI C : [2] [a]
"(\\. | [^ \\"]) * "
que significa "una cita; seguido de cero o más de un carácter de escape (barra invertida seguida de algo, posiblemente barra invertida o comilla), o un carácter que no sea de escape ni de comillas; termina en una cita"; el único problema es distinguir el cita final de una cita precedida por una barra invertida, que a su vez puede ser un escape. Varios personajes pueden seguir la barra invertida, por ejemplo \uFFFF
, según el esquema de escape.
Una cadena de escape debe entonces analizarse léxicamente , convirtiendo la cadena de escape en la cadena sin escape que representa. Esto se hace durante la fase de evaluación de la lexización global del lenguaje informático: el evaluador del lexer del lenguaje global ejecuta su propio lexer para los literales de cadena escapados.
Entre otras cosas, debe ser posible codificar el carácter que normalmente termina la constante de cadena, además 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 una cadena literal, 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 que 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 diferentes interpretaciones según el contexto y el idioma, pero generalmente son una especie de "comando de procesamiento" para representar caracteres impresos o no impresos.
Por ejemplo, en un literal de cadena C , si la barra invertida va seguida de una letra como "b", "n" o "t", esto representa un retroceso no imprimible , una nueva línea o un carácter de tabulación , respectivamente. O si la barra invertida va seguida de 1-3 dígitos octales , esta secuencia se interpreta como la representación del carácter arbitrario con el código ASCII especificado . Esto se amplió más tarde para permitir una notación de código de caracteres hexadecimales más moderna :
"Dije, \ t \ t \ x22Ca n ¿me escuchaste? \ X22 \ n "
Secuencia de escape | Unicode | Caracteres literales colocados en una cadena |
---|---|---|
\ 0 | U + 0000 | carácter nulo [3] [4] (típicamente como un caso especial de notación octal \ ooo) |
\a | U + 0007 | alerta [5] [6] |
\B | U + 0008 | retroceso [5] |
\F | U + 000C | alimentación de formulario [5] |
\norte | U + 000A | salto de línea [5] (o nueva línea en POSIX) |
\ r | U + 000D | retorno de carro [5] (o nueva línea en Mac OS 9 y versiones anteriores) |
\ t | U + 0009 | pestaña horizontal [5] |
\ v | U + 000B | pestaña vertical [5] |
\mi | U + 001B | carácter de escape [6] ( GCC , [7] clang y tcc ) |
\ u #### | U + #### | Carácter Unicode de 16 bits donde #### son cuatro dígitos hexadecimales [4] |
\ U ######## | U + ###### | Carácter Unicode de 32 bits donde ######## son ocho dígitos hexadecimales (el espacio de caracteres Unicode tiene actualmente solo 21 bits de ancho, por lo que los dos primeros dígitos hexadecimales siempre serán cero) |
\ u {######} | U + ###### | Carácter Unicode de 21 bits donde ###### es un número variable de dígitos hexadecimales |
\X## | U + 00 ## | Especificación de caracteres de 8 bits donde # es un dígito hexadecimal [5] |
\ ooo | U + 0 ### | Especificación de caracteres de 8 bits donde o es un dígito octal [5] |
\ " | U + 0022 | comillas dobles (") [5] |
\ & | no carácter utilizado para delimitar escapes numéricos en Haskell [3] | |
\ ' | U + 0027 | comilla simple (') [5] |
\\ | U + 005C | barra invertida (\) [5] |
\? | U + 003F | signo de interrogación (?) [5] |
Nota: No todas las secuencias de la lista son compatibles con todos los analizadores y puede haber otras secuencias de escape que no están en la lista.
Escapar anidado
Cuando el código de un lenguaje de programación está incrustado dentro de otro, las cadenas incrustadas pueden requerir varios niveles de escape. Esto es particularmente común en expresiones regulares y consultas SQL dentro de otros lenguajes, u otros lenguajes dentro de scripts de shell. Este doble escape es a menudo difícil de leer y de escribir.
Las citas incorrectas de cadenas anidadas pueden presentar una vulnerabilidad de seguridad. El uso de datos que no son de confianza, como en los campos de datos de una consulta SQL, debe usar declaraciones 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 de las cadenas (por conveniencia y seguridad), pero debido a problemas se eliminó de la versión 5.4 en adelante.
Cuerdas crudas
Algunos idiomas proporcionan un método para especificar que un literal debe procesarse sin ninguna interpretación específica del idioma. Esto evita la necesidad de escapar y produce cadenas más legibles.
Las cadenas sin formato son particularmente útiles cuando es necesario escapar de un carácter común, especialmente en expresiones regulares (anidadas como cadenas literales), donde la barra invertida \
se usa ampliamente, y en las 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 utilizando hilos crudos. 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 ocurren cuando se combinan: las rutas de la Convención de nomenclatura uniforme comienzan con \\
y, por lo tanto, una expresión regular de escape que coincide con un nombre UNC comienza con 8 barras diagonales inversas "\\\\\\\\"
, debido a la necesidad de escapar de la cadena y la expresión regular. El uso de cadenas sin formato reduce esto a 4 (escapando en la expresión regular), como en C # @"\\\\"
.
En documentos XML, las secciones CDATA permiten el uso de caracteres como & y
}]]>
Literales de cadena de varias líneas
En muchos idiomas, los literales de cadena pueden contener líneas nuevas literales, que abarcan varias líneas. Alternativamente, las nuevas líneas se pueden escapar, la mayoría de las veces como \n
. Por ejemplo:
echo 'foo bar'
y
echo -e "foo \ nbar"
son ambos bash válidos, produciendo:
foobar
Los lenguajes que permiten nuevas líneas literales incluyen bash, Lua, Perl, PHP, R y Tcl. En algunos otros idiomas, los literales de cadena no pueden incluir nuevas líneas.
Dos problemas con los literales de cadenas 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, particularmente para la primera línea, que a menudo tiene una sangría diferente al resto. Además, el literal debe estar sin sangría, ya que se conservan los espacios en blanco iniciales; esto interrumpe el flujo del código si el literal aparece dentro del código sangrado.
La solución más común para estos problemas son los literales de cadena de estilo documento . Hablando formalmente, un documento aquí no es un literal de cadena, sino un literal de flujo o un literal de archivo. Estos se originan en scripts de shell y permiten alimentar un literal como entrada a un comando externo. El delimitador de apertura es <
END
puede estar cualquier palabra, y el delimitador de cierre está END
en una línea por sí mismo, que sirve como límite de contenido; <<
se debe a que se redirige stdin desde el literal. Debido a que el delimitador es arbitrario, estos también evitan el problema de la colisión del delimitador. Estos también permiten eliminar las pestañas iniciales mediante la sintaxis variante, <<-END
aunque los espacios iniciales no se eliminan. Desde entonces, se ha adoptado la misma sintaxis para literales de cadenas de varias líneas en varios idiomas, sobre todo Perl, y también se los denomina aquí documentos, y retienen la sintaxis, a pesar de ser cadenas y no implican redirección. Al igual que con otros literales de cadena, estos a veces pueden tener un comportamiento diferente especificado, como la interpolación de variables.
Python, cuyos literales de cadena habituales no permiten nuevas líneas literales, en su lugar tiene una forma especial de cadena, diseñada para literales de varias líneas, llamada comillas triples . Estos utilizan un delimitador triplicado, ya sea '''
o """
. Estos literales se utilizan especialmente para la documentación en línea, conocida como cadenas de documentos .
Tcl permite líneas nuevas 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í mismos y las líneas nuevas iniciales y finales se eliminan mediante string trim
, mientras que string map
se pueden usar para eliminar la sangría.
Concatenación literal de cadena
Algunos lenguajes proporcionan concatenación literal 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, [8] [9] C ++, [10] D, [11] Ruby, [12] y Python, [13] que la copió de C. [14] Notablemente, esta concatenación ocurre en la compilación tiempo, durante el análisis léxico (como una fase después de la tokenización inicial), y se contrasta con la concatenación de cadenas en tiempo de ejecución (generalmente con el +
operador) [15] y 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 frase o "parsing"). La mayoría de los lenguajes, como C #, Java [16] y Perl, no admiten la concatenación literal de cadenas implícita 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 ++ - vea abajo); en este caso, la concatenación puede ocurrir en tiempo de compilación, mediante un plegado constante, o puede diferirse para el tiempo de ejecución.
Motivación
En C, donde se originan el concepto y el término, la concatenación literal de cadena se introdujo por dos razones: [17]
- Para permitir que las cadenas largas abarquen varias líneas con la sangría adecuada en contraste con la continuación de línea, lo que destruye el esquema de sangría; y
- Para permitir la construcción de cadenas literales mediante macros (a través de cadenas ). [18]
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 requerir análisis de frases o plegamiento constante. Por ejemplo, los siguientes son C / C ++ válidos:
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 pueden agregar; esto no es una restricción en la mayoría de los otros idiomas.char [n]
const char [n]
Esto es particularmente importante cuando se usa en combinación con el preprocesador de C , para permitir que las cadenas se calculen después del preprocesamiento, particularmente en macros. [14] Como ejemplo sencillo:
char * file_and_message = __FILE__ ": mensaje" ;
(si el archivo se llama ac) se expandirá a:
char * file_and_message = "ac" ": mensaje" ;
que luego se concatena, siendo equivalente a:
char * file_and_message = "ac: message" ;
Un caso de uso común es la construcción de cadenas de formato printf o scanf , donde los especificadores de formato vienen dados por macros. [19] [20]
Un ejemplo más complejo usa la cadena de números enteros (por el preprocesador) para definir una macro que se expande a una secuencia de cadenas literales, que luego se concatenan a una única cadena literal con el nombre del archivo y el número de línea: [21]
#define STRINGIFY (x) #x #define TOSTRING (x) STRINGIFY (x) #define AT __FILE__ ":" TOSTRING (__ LINE__)
Más allá de los requisitos sintácticos de C / C ++, la concatenación implícita es una forma de azúcar sintáctica , lo que simplifica la división de cadenas literales en varias líneas, evitando la necesidad de la continuación de línea (mediante barras diagonales inversas) y permitiendo agregar comentarios a partes de cadenas. Por ejemplo, en Python, uno puede comentar una expresión regular de esta manera: [22]
re . compilar ( "[A-Za-z_]" # letra o guión bajo "[A-Za-z0-9 _] *" # letra, dígito o guión bajo )
Problemas
Los compiladores modernos no requieren la concatenación implícita de cadenas, que implementan el plegado constante y provocan errores difíciles de detectar debido a la concatenación involuntaria al omitir una coma, particularmente en listas verticales de cadenas, como en:
l = [ 'foo' , 'bar' 'zork' ]
En consecuencia, no se usa en la mayoría de los lenguajes y se ha propuesto que se desaproveche de D [23] y Python. [14] Sin embargo, eliminar la función rompe la compatibilidad con versiones anteriores y reemplazarla con un operador de concatenación presenta problemas de precedencia: la concatenación literal de cadena ocurre durante la lexización, 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 ++, [24] 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 potencial de seguridad. [25]
Diferentes tipos de cuerdas.
Algunos lenguajes proporcionan más de un tipo de literal, que tiene un comportamiento diferente. Esto se usa particularmente para indicar cadenas sin formato (sin escape) o para deshabilitar o habilitar la interpolación de variables, pero tiene otros usos, como la distinción de conjuntos de caracteres. La mayoría de las veces, esto se hace cambiando el carácter entre 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 está en los scripts de shell, donde las comillas simples indican una cadena sin formato o "cadena literal", mientras que las comillas dobles tienen 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 ("bytes") de 8 bits (el valor predeterminado), indicadas explícitamente con un prefijo b
o B
, y cadenas Unicode, indicadas con un prefijo u
o U
. [26] mientras que en Python 3 las cadenas son Unicode por defecto y los bytes son un bytes
tipo separado que cuando se inicializan con comillas deben tener el prefijo b
.
La notación de C # para cadenas sin formato se llama @ -quoting.
@ "C: \ Foo \ Bar \ Baz \"
Si bien esto deshabilita el escape, permite las comillas dobles, lo que permite 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 anchas, 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 se consideran operadores más formalmente, y se conocen como operadores de cotización y similares . Estos incluyen tanto una sintaxis habitual (delimitadores fijos) como una sintaxis genérica, que permite elegir entre delimitadores; estos incluyen: [27]
'' "" `` // m // qr // s /// y // / q {} qq {} qx {} qw {} m {} qr {} s {} {} tr {} {} y {} {}
REXX usa caracteres de sufijo para especificar caracteres o cadenas usando su código hexadecimal o binario. P.ej,
'20' x"0010 0000" b"00100000" b
todos producen el carácter de espacio , evitando la llamada a la función X2C(20)
.
Interpolación variable
Los lenguajes difieren en si y cómo interpretar los literales de cadena como 'sin procesar' o 'variable interpolada'. La interpolación de variables es el proceso de evaluar una expresión que contiene una o más variables y devolver un resultado donde las variables se reemplazan con sus valores correspondientes en la memoria. En shells de Unix compatibles con sh (así como Perl y Ruby), las cadenas delimitadas por comillas (") se interpolan, mientras que las cadenas delimitadas por apóstrofos (') no. Por ejemplo, el siguiente código Perl :
$ nombre = "Nancy" ; $ saludo = "Hola mundo" ; print "$ name dijo $ saludando a la multitud". ;
produce la salida:
Nancy dijo Hola mundo a la multitud de personas.
El carácter sigilo ($) se interpreta para indicar interpolación variable.
De manera similar, la printf
función produce la misma salida usando una notación como:
printf "% s dijo% s a la multitud". , $ nombre , $ saludo ;
Los metacaracteres (% s) indican interpolación de variables.
Esto se contrasta con las cadenas "sin procesar":
print '$ name dijo $ saludo a la multitud de personas'. ;
que producen resultados como:
$ name dijo $ saludando a la multitud de personas.
Aquí los caracteres $ no son sigilos y no se interpreta que tengan otro significado que no sea texto plano.
Incrustar código fuente en cadenas literales
Los lenguajes que carecen de flexibilidad para especificar cadenas literales hacen que sea particularmente engorroso escribir código de programación que genere otro código de programación. Esto es particularmente cierto cuando el idioma de generación es el mismo o similar al idioma de salida.
Por ejemplo:
- escribiendo código para producir quines
- generar un lenguaje de salida desde dentro de una plantilla web ;
- usando XSLT para generar XSLT, o SQL para generar más SQL
- generar una representación PostScript de un documento con fines de impresión, desde una aplicación de procesamiento de documentos escrita en C o algún otro lenguaje.
- sombreadores de escritura
Sin embargo, algunos lenguajes están particularmente bien adaptados para producir este tipo de salida auto-similar, 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 implicaciones de seguridad adversas, especialmente si la salida se basa, al menos parcialmente, en una entrada de usuario que no es de confianza. Esto es particularmente grave en el caso de las aplicaciones basadas en web, donde los usuarios malintencionados pueden aprovechar tales debilidades para subvertir el funcionamiento de la aplicación, por ejemplo, montando un ataque de inyección SQL .
Ver también
- Carácter literal
- Literales XML
- Sigil (programación de computadoras)
Notas
- ^ La expresión regular dada aquí no se cita ni se escapa, para reducir la confusión.
Referencias
- ^ "Introducción a Java - MFC 158 G" .
Los literales de cadena (o constantes) se denominan 'cadenas anónimas'
- ^ "Gramática ANSI C (Lex)" . liu.se . Consultado el 22 de junio de 2016 .
- ^ a b "Apéndice B. Caracteres, cadenas y reglas de escape" . realworldhaskell.org . Consultado el 22 de junio de 2016 .
- ^ a b "Cadena" . mozilla.org . Consultado el 22 de junio de 2016 .
- ^ a b c d e f g h yo j k l m "Secuencias de escape (C)" . microsoft.com . Consultado el 22 de junio de 2016 .
- ^ a b "Justificación del estándar internacional - Lenguajes de programación - C" (PDF) . 5.10. Abril de 2003. págs. 52, 153–154, 159. Archivado (PDF) desde el original el 6 de junio de 2016 . Consultado el 17 de octubre de 2010 .
- ^ "6.35 El carácter en constantes" , Manual GCC 4.8.2 , consultado el 8 de marzo de 2014
- ^ Proyecto de norma C11 , Proyecto de comité WG14 N1570 - 12 de abril de 2011 , 5.1.1.2 Fases de traducción, p. 11: "6. Se concatenan los tokens literales de cadena adyacente".
- ^ C sintaxis: cadena de concatenación literal
- ^ C ++ 11 proyecto de estándar, "Borrador de trabajo, estándar para lenguaje de programación C ++" (PDF) ., 2.2 Fases de la traducción [lex.phases], pág. 17: "6. Los tokens literales de cadena adyacente están concatenados". y 2.14.5 Literales de cadena [lex.string], nota 13, p. 28-29: "En la fase de traducción 6 (2.2), las cadenas literales adyacentes se concatenan".
- ^ D Lenguaje de programación , análisis léxico , "Literales de cadena": "Las cadenas adyacentes se concatenan con el operador ~ o por yuxtaposición simple:"
- ^ ruby: The Ruby Programming Language , Ruby Programming Language, 2017-10-19 , consultado el 2017-10-19
- ^ La referencia del lenguaje Python, 2. Análisis léxico, 2.4.2. Concatenación literal de cadena : "Se permiten varios literales de cadena adyacentes (delimitados por espacios en blanco), posiblemente usando diferentes convenciones de comillas, y su significado es el mismo que su concatenación".
- ^ a b c Python-ideas, "¿Se considera dañina la concatenación literal de cadena implícita? ", Guido van Rossum, 10 de mayo de 2013
- ^ La referencia del lenguaje Python, 2. Análisis léxico, 2.4.2. Concatenación literal de cadena : "Tenga en cuenta que esta característica se define a nivel sintáctico, pero se implementa en tiempo de compilación. El operador '+' debe usarse para concatenar expresiones de cadena en tiempo de ejecución".
- ^ "Cadenas (Tutoriales de Java ™> Aprendizaje del lenguaje Java> Números y cadenas)" . Docs.oracle.com . 2012-02-28 . Consultado el 22 de junio de 2016 .
- ^ Justificación de la programación ANSI C Lenguaje . Silicon Press. 1990. p. 31 . ISBN 0-929306-07-4., 3.1.4 Literales de cadena : "Una cadena larga se puede continuar a lo largo de varias líneas utilizando la continuación de línea de barra inclinada invertida-nueva línea, pero esta práctica requiere que la continuación de la cadena comience en la primera posición de la línea siguiente. Para permitir más flexibilidad diseño, y para resolver algunos problemas de preprocesamiento (ver §3.8.3), el Comité introdujo la concatenación literal de cadena. Dos literales de cadena en una fila se pegan juntas (sin un carácter nulo en el medio) para hacer una literal de cadena combinada. Esta adición al lenguaje C permite a un programador extender un literal de cadena más allá del final de una línea física sin tener que usar el mecanismo de barra invertida-nueva línea y, por lo tanto, destruir el esquema de sangría del programa. No se introdujo un operador de concatenación explícito porque la concatenación es un construcción léxica en lugar de una operación en tiempo de ejecución ".
- ^ Justificación de la programación ANSI C Lenguaje . Silicon Press. 1990. p. 6566 . ISBN 0-929306-07-4., 3.8.3.2 El operador # : "El operador # se ha introducido para el encadenamiento. Solo se puede utilizar en una expansión #define. Hace que el nombre del parámetro formal siguiente sea reemplazado por un literal de cadena formado al encadenar el token de argumento real secuencia. Junto con la concatenación literal de cadena (ver §3.1.4), el uso de este operador permite la construcción de cadenas de manera tan efectiva como mediante el reemplazo de identificador dentro de una cadena. Un ejemplo en el Estándar ilustra esta característica. "
- ^ Diario de usuarios de C / C ++, volumen 19, p. 50
- ^ "Python - ¿Por qué permitir la concatenación de cadenas literales?" . Desbordamiento de pila . Consultado el 22 de junio de 2016 .
- ^ "LINE__ para encadenar (encadenar) usando directivas de preprocesador" . Decompile.com . 2006-10-12 . Consultado el 22 de junio de 2016 .
- ^ La referencia del lenguaje Python, 2. Análisis léxico, 2.4.2. Concatenación literal de cadenas : "Esta función se puede usar para reducir la cantidad de barras invertidas necesarias, para dividir cadenas largas de manera conveniente en líneas largas o incluso para agregar comentarios a partes de cadenas, por ejemplo:
- ^ Sistema de seguimiento de problemas de DLang - Problema 3827 - Advierte y luego desaprueba la concatenación implícita de cadenas literales adyacentes
- ^ C ++ 11 proyecto de estándar, "Borrador de trabajo, estándar para lenguaje de programación C ++" (PDF) ., 2.14.5 Literales de cadena [lex.string], nota 13, p. 28-29: "Cualquier otra concatenación se admite condicionalmente con un comportamiento definido por la implementación".
- ^ "Copia archivada" . Archivado desde el original el 14 de julio de 2014 . Consultado el 3 de julio de 2014 .CS1 maint: copia archivada como título ( enlace )
- ^ "2. Análisis léxico - documentación de Python 2.7.12rc1" . python.org . Consultado el 22 de junio de 2016 .
- ^ "perlop - perldoc.perl.org" . perl.org . Consultado el 22 de junio de 2016 .
enlaces externos
- Literales en programación