stringtranslate.com

Literal de cadena

Un literal de cadena o cadena anónima [1] es un literal para un valor de cadena en el código fuente de un programa de computadora . Los lenguajes de programación modernos suelen utilizar una secuencia de caracteres entre comillas, formalmente "delimitadores entre corchetes", como en x = "foo", donde "foo"hay una cadena literal con valor foo. Se pueden utilizar métodos como las secuencias de escape para evitar el problema de la colisión de delimitadores (problemas con corchetes) y permitir que los delimitadores se incrusten en una cadena. Existen muchas notaciones alternativas para especificar cadenas literales, 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.

Sintaxis

Delimitadores entre corchetes

La mayoría de los lenguajes de programación modernos utilizan delimitadores entre corchetes (también delimitadores equilibrados ) 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 entre ellas:

""

Algunos lenguajes 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 dar una semántica ligeramente diferente):

'¡Hola!'

Estas comillas no están emparejadas (el mismo carácter se utiliza para abrir y cerrar), lo cual es un vestigio de la tecnología de las máquinas de escribir , que fue la precursora de los primeros dispositivos de entrada y salida de las computadoras.

En términos de expresiones regulares , un literal de cadena entrecomillado básico se proporciona como:

"[^"]*"

Esto significa que un literal de cadena se escribe como: una comilla, seguida de cero, uno o más caracteres sin comillas, seguida de una comilla . En la práctica, esto suele complicarse con el uso de escapes, otros delimitadores y la exclusión de 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 se pueden incrustar delimitadores, siempre que estén emparejados, pero aún así se produce una colisión de delimitadores al 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 son sintácticamente lo mismo en Tcl que las cadenas literales; que los delimitadores estén emparejados es esencial para que esto sea factible.

El conjunto de caracteres Unicode incluye versiones emparejadas (apertura y cierre separadas) 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 utilizar en Visual Basic .NET ). 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 idiomas donde 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 nuevas líneas.

Un ejemplo son los parámetros de la plantilla MediaWiki .

{{Cuadro de navegación |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 la posición relativa 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 una sangría.        

Sin delimitadores

Algunos lenguajes de programación, como Perl y PHP, permiten cadenas literales sin delimitadores en algunos contextos. En el siguiente programa Perl, por ejemplo, red, greeny blueson cadenas literales, pero no están entre comillas:

% 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 dos líneas siguientes 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 llamada notación Hollerith , donde un recuento decimal del número de caracteres iba seguido de la letra H y luego de los caracteres de la cadena:

35 HAn ejemplo de literal de cadena Hollerith    

Este estilo de notación declarativa contrasta con las comillas delimitadoras entre corchetes , porque no requiere el uso de caracteres "entre corchetes" equilibrados en ninguno de los lados de la cadena.

Ventajas:

Desventajas:

Sin embargo, esto no supone un inconveniente cuando el prefijo lo genera un algoritmo, como suele ser el caso. [ cita necesaria ]

Funciones constructoras

C++ tiene dos estilos de cadena, uno heredado de C (delimitado por ") y el más seguro std::stringen la biblioteca estándar de C++. La std::stringclase se usa con frecuencia de la misma manera que se usaría un literal de cadena en otros lenguajes 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::stringgeneralmente asigna memoria dinámicamente y debe copiar el literal de cadena estilo C en tiempo de ejecución.

Antes de C++ 11, no había un literal para las cadenas de C++ (C++ 11 lo permite "this is a C++ string"scon sal final del literal), por lo que se usaba la sintaxis normal del constructor, por ejemplo:

todos los cuales tienen la misma interpretación. Desde C++ 11, también hay una nueva sintaxis de constructor:

Colisión delimitadora

Cuando se utilizan comillas, si uno desea representar el delimitador en sí en una cadena literal, se encuentra con 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 mediante el literal, """ya que la segunda comilla se interpreta como el final de la cadena literal, no como el valor de la cadena, y de manera similar no se puede escribir "This is "in quotes", but invalid."como la parte citada en el medio se interpreta como fuera de 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 existen 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 simplemente incluir, como en {}}.

Duplicando

Varios lenguajes, incluidos Pascal , BASIC , DCL , Smalltalk , SQL , J y Fortran , evitan la colisión de delimitadores duplicando las comillas que deben formar parte de la cadena literal:

 'Esta cadena de Pascal '' contiene dos apóstrofes '' '
 "Dije: "¿Puedes oírme?"""

cita dual

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 cotización dual . Normalmente, esto consiste en permitir que el programador utilice comillas simples o dobles indistintamente; cada literal debe utilizar una u otra.

 "Esta es la manzana de John".  'Le dije: "¿Puedes oírme?"'

Sin embargo, esto no permite tener un único literal con ambos delimitadores. Esto se puede solucionar usando varios literales y usando concatenación de cadenas :

 'Dije: "Esta es '  +  "John's"  +  ' manzana".'

Python tiene concatenación de cadenas literales , 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' ".'

Cotización delimitadora

C++ 11 introdujo los llamados literales de cadena sin formato . Consisten, esencialmente en

R" ID de fin de cadena ( contenido ) ID de fin de cadena " ,

es decir, después R"el programador puede ingresar hasta 16 caracteres, excepto espacios en blanco, paréntesis o barra invertida, que forman el id-fin de cadena (su propósito es repetirse para señalar el final de la cadena, eos id para abreviar ), entonces se requiere un paréntesis de apertura (para indicar el final de la identificación de eos). Luego sigue el contenido real del literal: se puede usar cualquier carácter de secuencia (excepto que no contenga un paréntesis de cierre seguido del eos id seguido de una comilla) y, finalmente, para terminar la cadena, un paréntesis de cierre, el eos id. , y se requiere una cotización.
El caso más simple de un literal de este tipo es con contenido vacío y eos id vacío: R"()".
La identificación de eos puede contener comillas: R""(I asked, "Can you hear me?")""es un literal válido (la identificación de eos está "aquí).
Las secuencias de escape no funcionan en literales de cadena sin formato.

D admite algunos delimitadores de 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 q"(A pair "()" of parens in quotes)"es un literal válido; un ejemplo con el carácter no anidado /es q"/I asked, "Can you hear me?"/".
Similar a C++ 11, D permite literales de estilo documento aquí con identificadores de fin de cadena:

q" fin de cadena-id contenido de nueva línea nueva línea fin de cadena-id "

En D, el ID de fin de cadena debe ser un identificador (caracteres alfanuméricos).

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, y por lo tanto se debe tener cuidado al elegir qué delimitador usar; Vea diferentes tipos de cuerdas a continuación.

Citas múltiples

Una extensión adicional es el uso de comillas múltiples , que permiten 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. Una variante de las comillas múltiples es el uso de cadenas de estilo documento .

Lua (a partir de 5.1) proporciona una forma limitada de citas 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 eliminada, 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 predeterminados se pueden reemplazar por otro carácter, como en .s/regex/replacement//s,regex,replacement,

Funciones constructoras

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. Generalmente, 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 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 entre comillas en un sistema ASCII se escribiría

"Dije: " + CHR$ ( 34 ) + "¿Puedes oírme?" + CH$ ( 34 )      

En C, hay disponible una función similar a través sprintfdel %cespecificador de formato "carácter", aunque en presencia de otras soluciones esto generalmente no se utiliza:

búfer de caracteres [ 32 ] ; snprintf ( búfer , tamaño del búfer , "Esto es %cin comillas.%c" , 34 , 34 );      

Estas funciones constructoras también se pueden utilizar para representar caracteres que no se imprimen, aunque generalmente se utilizan secuencias de escape. Se puede utilizar una técnica similar en C++ con el std::stringoperador de encadenamiento.

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 espacios en blanco (que de otro modo serían imposibles de distinguir visualmente), y tienen una larga historia. En consecuencia, se utilizan ampliamente en cadenas literales 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 proporcionar codificaciones de caracteres que son difíciles o imposibles de incluir directamente. Lo más común es que sea una barra invertida ; Además de otros caracteres, un punto clave es que la barra invertida en sí se puede codificar como una barra invertida doble \\y, para cadenas delimitadas, el delimitador en sí se puede codificar mediante un sistema de escape, por ejemplo, con \"". Una expresión regular para dichas cadenas con escape se puede proporcionar de la siguiente manera , como se encuentra en la especificación ANSI C : [2] [a]

"(\\.|[^\\"])*"

que significa "una comilla; seguida de cero o más de un carácter de escape (barra invertida seguida de algo, posiblemente barra invertida o comillas), o un carácter sin escape ni comillas; que termina en una comilla"; el único problema es distinguir el terminando la cita a partir de una cita precedida por una barra invertida, que a su vez puede tener un carácter de escape. Varios caracteres pueden seguir a la barra invertida, como \uFFFF, según el esquema de escape.

Luego, una cadena con escape debe analizarse léxicamente , convirtiendo la cadena con escape en la cadena sin escape que representa. Esto se hace durante la fase de evaluación del lexing general del lenguaje informático: el evaluador del lexer del lenguaje general 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 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. La cantidad 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 una cadena literal.

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 imprimibles.

Por ejemplo, en un literal de cadena C , si la barra invertida va seguida de una letra como "b", "n" o "t", entonces esto representa un carácter de retroceso , nueva línea o tabulación que no se imprime , 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 arbitrario con el valor especificado en la codificación del literal (por ejemplo, el código ASCII correspondiente para un literal ASCII). Posteriormente, esto se amplió para permitir una notación de códigos de caracteres hexadecimales más moderna:

"Dije: \t\t\x22¿Puedes oírme? \x22\n "

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.

escape anidado

Cuando el código de un lenguaje de programación está incrustado 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 u otros lenguajes dentro de scripts de shell. Este doble escape suele ser difícil de leer y redactar.

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 utilizar declaraciones preparadas para evitar un ataque de inyección de código . En PHP 2 a 5.3, había una característica llamada comillas mágicas que escapaban automáticamente las cadenas (por conveniencia y seguridad), pero debido a problemas se eliminó a partir de la versión 5.4.

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 un carácter común, especialmente en expresiones regulares (anidadas como cadenas literales), 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 utilizando cuerdas crudas. Compare nombres de ruta de escape y sin formato en C#:

 "La ruta de Windows es C:\\Foo\\Bar\\Baz\\" @"La ruta de Windows es C:\Foo\Bar\Baz\" 

Se producen ejemplos extremos 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 invertidas."\\\\\\\\" 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 < sin que un analizador XML intente interpretarlos como parte de la estructura del documento en sí. Esto puede resultar útil al incluir texto literal y código de script para mantener el documento bien formado .

<![CDATA[ if (ruta!=null && profundidad<2) { add(ruta); } ]]>

Literales de cadena multilínea

En muchos idiomas, las cadenas literales pueden contener nuevas líneas literales, que abarcan varias líneas. Alternativamente, se pueden escapar las nuevas líneas, generalmente como \n. Por ejemplo:

eco ' barra foo ' 

y

eco  -e "foo\nbar" 

Ambos son bash válidos y producen:

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 multilínea son las nuevas líneas iniciales y finales y la sangría. Si los delimitadores iniciales o finales 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 no debe tener sangría, ya que se conservan los espacios en blanco iniciales; esto interrumpe el flujo del código si el literal ocurre dentro del código con sangría.

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 secuencia o un literal de archivo. Estos se originan en scripts de shell y permiten que un literal se envíe como entrada a un comando externo. El delimitador de apertura es <<ENDdonde ENDpuede estar cualquier palabra, y el delimitador de cierre está ENDen una línea sola, sirviendo como límite de contenido; esto <<se debe a la redirección de la entrada estándar 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 eliminar las pestañas iniciales mediante la sintaxis variante, <<-ENDaunque los espacios iniciales no se eliminan. Desde entonces, se ha adoptado la misma sintaxis para literales de cadenas multilínea en varios idiomas, sobre todo Perl, y aquí también se los denomina documentos, y conservan la sintaxis, a pesar de ser cadenas y no implicar redirección. Al igual que con otros literales de cadena, 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, tiene en cambio una forma especial de cadena, diseñada para literales multilínea, llamada comillas triples . Estos utilizan un delimitador triplicado, ya sea '''o """. Estos literales se utilizan especialmente para documentación en línea, conocidos como cadenas de documentos. .

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í mismos y las nuevas líneas iniciales y finales se eliminan mediante string trim, mientras que string mapse pueden usar para eliminar la sangría.

Concatenación literal de cadenas

Algunos lenguajes proporcionan concatenación de literales de cadenas , donde los literales de cadenas adyacentes se unen implícitamente en un único literal en el momento de la compilación. Esta es una característica de C, [8] [9] C++, [10] D, [11] Ruby, [12] y Python, [13] que la copiaron de C. [14] En particular, 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 tanto con la concatenación de cadenas en tiempo de ejecución (generalmente con el +operador) [15] como con la concatenación durante el plegado constante , que ocurre en el tiempo de compilación, pero en una fase posterior ( después del análisis de frases o "análisis"). La mayoría de los lenguajes, como C#, Java [16] y Perl, no admiten la concatenación literal de cadenas implícitas 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 plegado constante, o puede diferirse hasta el tiempo de ejecución.

Motivación

En C, donde se originan el concepto y el término, la concatenación literal de cadenas se introdujo por dos razones: [17]

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 ni plegado 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 tipo de matriz , (C) ochar [n]const char [n] (C++), que no se pueden agregar; esto no es una restricción en la mayoría de los demás idiomas.

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" ;    

se expandirá (si el archivo se llama ac) a:

char * file_and_message = "ac" ": mensaje" ;    

que luego se concatena, siendo equivalente a:

char * file_and_message = "ac: mensaje" ;   

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 utiliza 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 en una única cadena literal con el nombre del archivo y el número de línea: [21]

#definir STRINGIFY(x) #x #definir TOSTRING(x) STRINGIFY(x) #definir 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áctico , lo que simplifica la división de literales de cadena en varias líneas, evita la necesidad de continuación de línea (mediante barras invertidas) y permite agregar comentarios a partes de las cadenas. Por ejemplo, en Python, se 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 de cadenas implícita, que implementan el plegado constante y provoca 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' ,  'barra'  'zork' ]

En consecuencia, no se utiliza en la mayoría de los lenguajes y se ha propuesto su desuso desde D [23] y Python. [14] 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 literal de cadena ocurre durante la lexing, 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 garantizar el orden de evaluación deseado.

Un problema más sutil es que en C y C++, [24] existen diferentes tipos de cadenas literales, y la concatenación de estas tiene un comportamiento definido por la implementación, lo que plantea un riesgo potencial de seguridad. [25]

Diferentes tipos de cuerdas

Algunos idiomas 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 distinguir conjuntos de caracteres. En la mayoría de los casos, esto se hace cambiando el carácter de las comillas o agregando un prefijo o sufijo. Esto es comparable a los prefijos y sufijos de 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 tienen secuencias de escape e interpolación variable.

Por ejemplo, en Python , las cadenas sin formato están precedidas por ro R– comparar '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 el prefijo bo B, y cadenas Unicode, indicadas con el prefijo uo U. [26] mientras que en Python 3 las cadenas son Unicode de forma predeterminada y los bytes son un bytestipo 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 desactiva el escape, permite 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 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 entre comillas 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 utiliza caracteres de sufijo para especificar caracteres o cadenas utilizando 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 de cadenas

En algunos idiomas, las cadenas literales 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 variable o, más generalmente, interpolación de cadenas . Los lenguajes que admiten la interpolación generalmente distinguen las cadenas literales que se interpolan de las que no. Por ejemplo, en 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 a veces se denominan "cadenas sin formato", pero esto se diferencia de "cadena sin formato" en el sentido de escape. Por ejemplo, en Python, una cadena con el prefijo ro Rno tiene escape ni interpolación, una cadena normal (sin prefijo). ) tiene escape pero no interpolación, y una cadena con el prefijo fo Ftiene escape e interpolación.

Por ejemplo, el siguiente código Perl :

$nombre = "Nancy" ; $saludo = "Hola mundo" ; print "$nombre dijo $saludo a la multitud." ;     

produce la salida:

Nancy dijo Hola Mundo a la multitud.

En este caso, el carácter metacarácter ($) (no debe confundirse con el sigilo en la declaración de asignación de variables) se interpreta para indicar interpolación de variables y requiere algo de escape si es necesario generarlo literalmente.

Esto debe contrastarse con la printffunción, que produce el mismo resultado usando notación como:

printf "%s dijo %s a la multitud." , $nombre , $saludo ;   

pero no realiza interpolación: %ses un marcador de posición en una cadena en formato printf , pero las variables mismas están fuera de la cadena.

Esto se contrasta con las cadenas "sin procesar":

print '$nombre dijo $saludo a la multitud de personas.' ; 

que producen resultados como:

$name dijo $saludando a la multitud de personas.

Aquí los caracteres $ no son metacaracteres y no se interpreta que tengan ningún otro significado que no sea texto sin formato.

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 igual o similar al idioma de salida.

Por ejemplo:

Sin embargo, algunos lenguajes están particularmente bien adaptados para producir este tipo de resultados autosemejantes, 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 entradas de usuarios que no son de confianza. Esto es particularmente grave en el caso de las aplicaciones basadas en Web, donde los usuarios malintencionados pueden aprovechar dichas debilidades para subvertir el funcionamiento de la aplicación, por ejemplo montando un ataque de inyección SQL .

Ver también

Notas

  1. ^ La expresión regular proporcionada aquí no se cita ni se escapa, para reducir la confusión.
  2. ^ ab Dado que esta secuencia de escape representa una unidad de código específica en lugar de un carácter específico, el punto de código (si corresponde) que representa depende de la codificación de la cadena literal en la que se encuentra.

Referencias

  1. ^ "Introducción a Java: MFC 158 G". Las cadenas literales (o constantes) se denominan "cadenas anónimas".
  2. ^ "Gramática ANSI C (Lex)". liu.se. ​Consultado el 22 de junio de 2016 .
  3. ^ ab "Apéndice B. Caracteres, cadenas y reglas de escape". realworldhaskell.org . Consultado el 22 de junio de 2016 .
  4. ^ ab "Cadena". mozilla.org . Consultado el 22 de junio de 2016 .
  5. ^ abcdefghijklm "Secuencias de escape (C)". microsoft.com . Consultado el 22 de junio de 2016 .
  6. ^ ab "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 .
  7. ^ "6.35 El carácter <ESC> en constantes", Manual GCC 4.8.2 , consultado el 8 de marzo de 2014
  8. ^ Borrador del estándar C11 , Borrador del Comité WG14 N1570 - 12 de abril de 2011, 5.1.1.2 Fases de traducción, p. 11: "6. Los tokens literales de cadenas adyacentes están concatenados".
  9. ^ Sintaxis C: concatenación literal de cadenas
  10. ^ Borrador de estándar C ++ 11 , "Borrador de trabajo, estándar para el lenguaje de programación C ++" (PDF) ., 2.2 Fases de la traducción [lex.phases], p. 17: "6. Los tokens literales de cadena adyacentes están concatenados". y 2.14.5 Literales de cadena [lex.string], nota 13, pág. 28–29: "En la fase de traducción 6 (2.2), los literales de cadena adyacentes se concatenan".
  11. ^ Lenguaje de programación D, análisis léxico, "literales de cadena": "Las cadenas adyacentes se concatenan con el operador ~ o mediante yuxtaposición simple:"
  12. ^ ruby: el lenguaje de programación Ruby, lenguaje de programación Ruby, 19 de octubre de 2017 , consultado el 19 de octubre de 2017
  13. ^ Referencia del lenguaje Python, 2. Análisis léxico, 2.4.2. Concatenación de literales de cadena: "Se permiten múltiples 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".
  14. ^ abc Python-ideas, "¿La concatenación literal de cadenas implícita se considera dañina?", Guido van Rossum, 10 de mayo de 2013
  15. ^ 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 en el 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".
  16. ^ "Cadenas (Tutoriales de Java™ > Aprendizaje del lenguaje Java > Números y cadenas)". Docs.oracle.com . 28 de febrero de 2012 . Consultado el 22 de junio de 2016 .
  17. ^ Justificación del lenguaje de programación ANSI C. Prensa de silicio. 1990. pág. 31.ISBN 0-929306-07-4., 3.1.4 Literales de cadena: "Una cadena larga puede continuar en varias líneas utilizando la barra invertida y la continuación de línea de nueva línea, pero esta práctica requiere que la continuación de la cadena comience en la primera posición de la siguiente línea. Para permitir una mayor flexibilidad diseño y para resolver algunos problemas de preprocesamiento (ver §3.8.3), el Comité introdujo la concatenación de cadenas literales en una fila (sin ningún carácter nulo en el medio) para formar una cadena literal combinada. 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 nueva línea con barra invertida 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".
  18. ^ Justificación del lenguaje de programación ANSI C. Prensa de silicio. 1990. pág. 6566.ISBN 0-929306-07-4., 3.8.3.2 El operador #: "El operador # se ha introducido para la creación de cadenas. Solo puede usarse en una expansión #define. Hace que el nombre del parámetro formal siguiente se reemplace por una cadena literal formada al encadenar el token del argumento real. secuencia junto con la concatenación literal de cadenas (ver §3.1.4), el uso de este operador permite la construcción de cadenas tan efectivamente como mediante el reemplazo de identificadores dentro de una cadena. Un ejemplo en el Estándar ilustra esta característica.
  19. ^ Diario de usuarios de C/C++, volumen 19, p. 50
  20. ^ "python: ¿por qué permitir la concatenación de cadenas literales?". Desbordamiento de pila . Consultado el 22 de junio de 2016 .
  21. ^ "LINE__ a cadena (stringify) usando directivas de preprocesador". Descompile.com . 2006-10-12 . Consultado el 22 de junio de 2016 .
  22. ^ Referencia del lenguaje Python, 2. Análisis léxico, 2.4.2. Concatenación literal de cadenas: "Esta característica se puede utilizar para reducir el número de barras invertidas necesarias, para dividir cadenas largas cómodamente en líneas largas o incluso para agregar comentarios a partes de cadenas, por ejemplo:
  23. ^ Sistema de seguimiento de problemas de DLang - Problema 3827: advierte y luego desaprueba la concatenación implícita de literales de cadenas adyacentes
  24. ^ Borrador de estándar C++ 11 , "Borrador de trabajo, estándar para el 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".
  25. ^ "STR10-C. No concatene diferentes tipos de literales de cadena - Codificación segura - Estándares de codificación segura CERT". Archivado desde el original el 14 de julio de 2014 . Consultado el 3 de julio de 2014 .
  26. ^ "2. Análisis léxico: documentación de Python 2.7.12rc1". python.org . Consultado el 22 de junio de 2016 .
  27. ^ "perlop-perldoc.perl.org". perl.org . Consultado el 22 de junio de 2016 .

enlaces externos