"shlex" --- Análisis léxico simple
**********************************

**Código fuente:** Lib/shlex.py

======================================================================

La clase "shlex" facilita la escritura de analizadores léxicos para
sintaxis simples que se parecen al intérprete de comandos de Unix.
Esto será a menudo útil para escribir pequeños lenguajes, (por
ejemplo, en archivos de control para aplicaciones Python) o para
analizar cadenas de texto citadas.

El módulo "shlex" define las siguientes funciones:

shlex.split(s, comments=False, posix=True)

   Divide la cadena de caracteres *s* usando una sintaxis similar a la
   de un intérprete de comandos.  Si *comments* es "False" (por
   defecto), el análisis de los comentarios en la cadena de caracteres
   dada sera deshabilitada (estableciendo el atributo "commenters" de
   la instancia "shlex" a la cadena de caracteres vacía). Esta función
   trabaja en modo POSIX por defecto, pero utiliza el modo non-POSIX
   si el argumento *posix* es falso.

   Nota:

     Como la función "split()" inicia una instancia "shlex", al pasar
     "None" por *s* se leerá la cadena de caracteres para separarse de
     la entrada estándar.

shlex.join(split_command)

   Concatena los tokens de la lista *split_command* y retorna una
   cadena. Esta función es la inversa de "split()".

   >>> from shlex import join
   >>> print(join(['echo', '-n', 'Multiple words']))
   echo -n 'Multiple words'

   El valor retornado se escapa del intérprete de comandos para
   protegerlo contra vulnerabilidades de inyección (consulte
   "quote()").

   Nuevo en la versión 3.8.

shlex.quote(s)

   Retorna una versión con escape del intérprete de comandos de la
   cadena *s*.  El valor retornado es una cadena que se puede usar de
   forma segura como un token en un intérprete de línea de comandos,
   para los casos en los que no se puede usar una lista.

   Este idioma sería inseguro:

   >>> filename = 'somefile; rm -rf ~'
   >>> command = 'ls -l {}'.format(filename)
   >>> print(command)  # executed by a shell: boom!
   ls -l somefile; rm -rf ~

   "quote()" te permite tapar el agujero de seguridad:

   >>> from shlex import quote
   >>> command = 'ls -l {}'.format(quote(filename))
   >>> print(command)
   ls -l 'somefile; rm -rf ~'
   >>> remote_command = 'ssh home {}'.format(quote(command))
   >>> print(remote_command)
   ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''

   La cita es compatible con los intérpretes de comandos UNIX y con
   "split()":

   >>> from shlex import split
   >>> remote_command = split(remote_command)
   >>> remote_command
   ['ssh', 'home', "ls -l 'somefile; rm -rf ~'"]
   >>> command = split(remote_command[-1])
   >>> command
   ['ls', '-l', 'somefile; rm -rf ~']

   Nuevo en la versión 3.3.

El módulo "shlex" define las siguientes clases:

class shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False)

   Una instancia o instancia de la subclase "shlex" es un objeto de
   analizador léxico.  El argumento de inicialización, si está
   presente, especifica de dónde leer caracteres.  Debe ser un objeto
   similar a un archivo/stream con los métodos "read()" y "readline()"
   o una cadena de caracteres.  Si no se da ningún argumento, la
   entrada se tomará de "sys.stdin". El segundo argumento opcional es
   una cadena de nombre de archivo, que establece el valor inicial del
   atributo "infile".  Si el argumento *instream* es omitido o es
   igual a "sys.stdin", este segundo argumento tiene como valor
   predeterminado "stdin".  El argumento *posix* define el modo
   operativo: cuando *posix* no es true (predeterminado), la instancia
   "shlex" funcionará en modo de compatibilidad.  Cuando se opera en
   modo POSIX, "shlex" intentará estar lo más cerca posible de las
   reglas de análisis de el intérprete de comandos POSIX.  El
   argumento *punctuation_chars* proporciona una manera de hacer que
   el comportamiento sea aún más cercano a la forma en que se analizan
   los intérpretes de comandos reales.  Esto puede tomar una serie de
   valores: el valor predeterminado, "False", conserva el
   comportamiento visto en Python 3.5 y versiones anteriores.  Si se
   establece en "True", se cambia el análisis de los caracteres
   "();<>|&": cualquier ejecución de estos caracteres (caracteres
   considerados de puntuación) se retorna como un único token.  Si se
   establece en una cadena de caracteres no vacía, esos caracteres se
   utilizarán como caracteres de puntuación.  Los caracteres del
   atributo "wordchars" que aparecen en *punctuation_chars* se
   eliminarán de "wordchars".  Consulte Compatibilidad mejorada con
   intérprete de comandos para obtener más información.
   *punctuation_chars* solo se puede establecer en la creación de la
   instancia "shlex" y no se puede modificar más adelante.

   Distinto en la versión 3.6: Se añadió el parámetro
   *punctuation_chars*.

Ver también:

  Módulo "configparser"
     Analizador de archivos de configuración similares a los archivos
     ".ini" de Windows.


objetos "shlex"
===============

Una instancia "shlex" tiene los siguientes métodos:

shlex.get_token()

   Retorna un token.  Si los tokens han sido apiladas usando
   "push_token()", saca una ficha de la pila.  De lo contrario, lee
   uno de la secuencia de entrada.  Si la lectura encuentra un fin de
   archivo inmediato, "eof" se retorna (la cadena de caracteres vacía
   ("''") en modo no-POSIX, y "None" en modo POSIX).

shlex.push_token(str)

   Coloca el argumento en la pila de tokens.

shlex.read_token()

   Lee un token sin procesar. Ignora la pila de retroceso y no
   interpreta las peticiones de la fuente.  (Este no es normalmente un
   punto de entrada útil, y está documentado aquí sólo para
   completarlo.)

shlex.sourcehook(filename)

   Cuando "shlex" detecta una petición de fuente (ver "source" abajo)
   este método recibe el siguiente token como argumento, y se espera
   que retorne una tupla que consista en un nombre de archivo y un
   archivo abierto como objeto.

   Normalmente, este método primero elimina las comillas del
   argumento.  Si el resultado es un nombre de ruta absoluto, o no
   había ninguna solicitud de origen anterior en vigor, o el origen
   anterior era una secuencia (como "sys.stdin"), el resultado se deja
   solo.  De lo contrario, si el resultado es un nombre de ruta
   relativo, la parte del directorio del nombre del archivo se pone
   inmediatamente antes en la pila de inclusión de origen (este
   comportamiento es similar a la forma en que el preprocesador de C
   controla "#include "file.h"").

   El resultado de las manipulaciones se trata como un nombre de
   archivo y se retorna como el primer componente de la tupla, con
   "open()" llamado en él para producir el segundo componente. (Nota:
   esto es lo contrario del orden de los argumentos en la
   inicialización de instancia!)

   Este enlace se expone para que pueda usarlo para implementar rutas
   de búsqueda de directorios, adición de extensiones de archivo y
   otros trucos de espacios de nombres. No hay ningún enlace 'close'
   correspondiente, pero una instancia de "shlex" llamará el método
   "close()" de la secuencia de entrada de origen cuando retorna EOF.

   Para un control más explícito del apilamiento de código fuente,
   utilice los métodos "push_source()" y "pop_source()".

shlex.push_source(newstream, newfile=None)

   Inserta una secuencia de fuente de entrada en la pila de entrada.
   Si se especifica el argumento de nombre de archivo, más adelante
   estará disponible para su uso en mensajes de error.  Este es el
   mismo método utilizado internamente por el método "sourcehook()".

shlex.pop_source()

   Saca la última fuente de entrada de la pila de entrada. Este es el
   mismo método que el analizador léxico utiliza cuando llega al EOF
   en una secuencia de entrada apilada.

shlex.error_leader(infile=None, lineno=None)

   Este método genera un mensaje de error líder en el formato de una
   etiqueta de error del compilador de Unix C; el formato es "'"%s",
   line %d: '", donde el "%s" es reemplazado con el nombre del archivo
   fuente actual y el "%d" con el número de línea de entrada actual
   (los argumentos opcionales pueden ser usado para sobrescribir
   estos).

   Esta conveniencia se proporciona para animar a los usuarios de
   "shlex" a generar mensajes de error en el formato estándar y
   analizable que entienden Emacs y otras herramientas de Unix.

Las instancias de las subclases "shlex" tienen algunas variables de
instancia pública que controlan el análisis léxico o pueden ser usadas
para la depuración:

shlex.commenters

   La cadena de caracteres que son reconocidos como comentarios de
   principiantes. Todos los caracteres desde el comentario
   principiante hasta el final de la línea son ignorados. Incluye sólo
   "'#'" por defecto.

shlex.wordchars

   La cadena de caracteres que se acumulará en tokens de varios
   caracteres.  Por defecto, incluye todos los alfanuméricos ASCII y
   el subrayado.  En el modo POSIX, los caracteres acentuados del
   conjunto Latin-1 también están incluidos.  Si "punctuation_chars"
   no está vacío, los caracteres "~-./*?=", que pueden aparecer en las
   especificaciones del nombre de archivo y en los parámetros de la
   línea de comandos, también se incluirán en este atributo, y
   cualquier carácter que aparezca en "punctuation_chars" será
   eliminado de "wordchars" si están presentes allí. Si
   "whitespace_split" se establece en "True", esto no tendrá ningún
   efecto.

shlex.whitespace

   Caracteres que serán considerados como espacio en blanco y
   salteados.  El espacio blanco limita los tokens.  Por defecto,
   incluye espacio, tabulación, salto de línea y retorno de carro.

shlex.escape

   Caracteres que serán considerados como de escape. Esto sólo se
   usará en el modo POSIX, e incluye sólo "'\'" por defecto.

shlex.quotes

   Los caracteres que serán considerados como citas de la cadena.  El
   token se acumula hasta que la misma cita se encuentra de nuevo
   (así, los diferentes tipos de citas se protegen entre sí como en el
   intérprete de comandos.) Por defecto, incluye ASCII comillas
   simples y dobles.

shlex.escapedquotes

   Caracteres en "quotes" que interpretarán los caracteres de escape
   definidos en "escape".  Esto sólo se usa en el modo POSIX, e
   incluye sólo "'"'" por defecto.

shlex.whitespace_split

   Si es "True", los tokens sólo se dividirán en espacios en blanco.
   Esto es útil, por ejemplo, para analizar las líneas de comando con
   "shlex", obteniendo los tokens de forma similar a los argumentos de
   el intérprete de comandos.  Cuando se utiliza en combinación con
   "puntuation_chars", los tokens se dividirán en espacios en blanco
   además de esos caracteres.

   Distinto en la versión 3.8: El atributo "puntuation_chars" se hizo
   compatible con el atributo "whitespace_split".

shlex.infile

   El nombre del archivo de entrada actual, como se estableció
   inicialmente al momento de la instanciación de la clase o apilado
   por solicitudes de fuente posteriores.  Puede ser útil examinar
   esto cuando se construyan mensajes de error.

shlex.instream

   El flujo de entrada del cual esta instancia "shlex" está leyendo
   caracteres.

shlex.source

   Este atributo es "None" por defecto.  Si le asignas una cadena, esa
   cadena será reconocida como una solicitud de inclusión a nivel
   léxico similar a la palabra clave "source" en varios intérpretes de
   comandos.  Es decir, el token inmediatamente siguiente se abrirá
   como un nombre de archivo y la entrada se tomará de ese flujo hasta
   EOF, en cuyo momento se llamará al método "close()" de ese flujo y
   la fuente de entrada se convertirá de nuevo en el flujo de entrada
   original.  Las peticiones de origen pueden ser apiladas a cualquier
   número de niveles de profundidad.

shlex.debug

   Si este atributo es numérico y "1" o más, una instancia "shlex"
   imprimirá una salida de progreso verboso en su comportamiento.  Si
   necesitas usar esto, puedes leer el código fuente del módulo para
   conocer los detalles.

shlex.lineno

   Numero de linea de fuente (conteo de las nuevas lineas vistas hasta
   ahora mas uno).

shlex.token

   El buffer de tokens.  Puede ser útil examinarlo cuando se capturan
   excepciones.

shlex.eof

   Token usado para determinar el final del archivo. Esto se ajustará
   a la cadena de caracteres vacía ("''"), en el modo no-POSIX, y a
   "None" en el modo POSIX.

shlex.punctuation_chars

   Una propiedad de sólo lectura. Caracteres que serán considerados
   como puntuación. Las series de caracteres de puntuación se
   retornarán como un único token. Sin embargo, tenga en cuenta que no
   se realizará ninguna comprobación de validez semántica: por
   ejemplo, '>>>' podría ser retornado como un token, aunque no sea
   reconocido como tal por los intérpretes de comandos.

   Nuevo en la versión 3.6.


Reglas de análisis
==================

Cuando se opera en modo no-POSIX, "shlex" intentará obedecer las
siguientes reglas.

* Los caracteres entre comillas no son reconocidos dentro de las
  palabras ("Do"Not"Separate" es analizado como la única palabra
  "Do"Not"Separate");

* Los caracteres de escape no son reconocidos;

* El encerrar los caracteres entre comillas preserva el valor literal
  de todos los caracteres dentro de las comillas;

* Las comillas finales separan las palabras (""Do"Separate" es
  analizado como ""Do"" y "Separate");

* Si "whitepace_split" es "False", cualquier carácter que no sea
  declarado como un carácter de palabra, espacio en blanco, o una cita
  será retornado como un token de un solo carácter. Si es "True",
  "shlex" sólo dividirá las palabras en espacios en blanco;

* EOF es señalado con una cadena de caracteres vacía ("''");

* No es posible analizar cadenas de caracteres vacías, incluso si se
  citan.

Cuando se opera en el modo POSIX, "shlex" intentará obedecer a las
siguientes reglas de análisis.

* Las comillas se eliminan y no separan las palabras
  (""Do"Not"Separate"" se analiza como la sola palabra
  "DoNotSeparate");

* Los caracteres de escape no citados (por ejemplo "'\'") conservan el
  valor literal del siguiente carácter que continua;

* Encerrar caracteres entre comillas que no forman parte de
  "escapedquotes" (por ejemplo, """") conservan el valor literal de
  todos los caracteres dentro de las comillas;

* Encerrar caracteres entre comillas que forman parte de
  "escapedquotes" (por ejemplo, """") conserva el valor literal de
  todos los caracteres dentro de las comillas, con la excepción de los
  caracteres mencionados en "escape".  Los caracteres de escape
  conservan su significado especial solo cuando van seguidos de la
  comilla en uso, o el propio carácter de escape. De lo contrario, el
  carácter de escape sera considerado un carácter normal.

* EOF es señalado con un valor "None";

* Se permiten cadenas de caracteres vacías entrecomilladas ("''").


Compatibilidad mejorada con intérprete de comandos
==================================================

Nuevo en la versión 3.6.

La clase "shlex" provee compatibilidad con el análisis realizado por
los intérprete de comandos comunes de Unix como "bash", "dash" y "sh".
Para aprovechar esta compatibilidad, especifica el argumento
"punctuation_chars" en el constructor.  Esto por defecto es "False",
el cual conserva el comportamiento pre-3.6. Sin embargo, si se
establece como "True", entonces se cambia el análisis de los
caracteres "();<>|&": cualquier ejecución de estos caracteres se
retorna como un único token.  Mientras que esto se queda corto en un
analizador completo para los intérprete de comandos (que estaría fuera
del alcance de la biblioteca estándar, dada la multiplicidad de
intérpretes de comandos que hay), te permite realizar el procesamiento
de las líneas de comandos más fácilmente de lo que podrías hacerlo de
otra manera.  Para ilustrarlo, puede ver la diferencia en el siguiente
fragmento:

    >>> import shlex
    >>> text = "a && b; c && d || e; f >'abc'; (def \"ghi\")"
    >>> s = shlex.shlex(text, posix=True)
    >>> s.whitespace_split = True
    >>> list(s)
    ['a', '&&', 'b;', 'c', '&&', 'd', '||', 'e;', 'f', '>abc;', '(def', 'ghi)']
    >>> s = shlex.shlex(text, posix=True, punctuation_chars=True)
    >>> s.whitespace_split = True
    >>> list(s)
    ['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', 'abc', ';',
    '(', 'def', 'ghi', ')']

Por supuesto, se retornarán tokens que no son válidos para los
intérpretes de comandos y deberá implementar sus propias
comprobaciones de errores en los tokens retornados.

En lugar de pasar "True" como valor para el parámetro
punctuation_chars, puede pasar una cadena con caracteres específicos,
que se usará para determinar qué caracteres constituyen puntuación.
Por ejemplo:

   >>> import shlex
   >>> s = shlex.shlex("a && b || c", punctuation_chars="|")
   >>> list(s)
   ['a', '&', '&', 'b', '||', 'c']

Nota:

  Cuando es especificado "punctuation_chars", el atributo "wordchars"
  se aumenta con los caracteres "~-./*?=".  Esto se debe a que estos
  caracteres pueden aparecer en los nombres de archivo (incluidos los
  comodines) y en los argumentos de la línea de comandos (por ejemplo,
  "--color=auto"). Por lo tanto:

     >>> import shlex
     >>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?',
     ...                 punctuation_chars=True)
     >>> list(s)
     ['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']

  Sin embargo, para que coincida con el intérprete de comandos lo más
  cerca posible, se recomienda utilizar siempre "posix" y
  "whitespace_split" cuando se utiliza "punctuation_chars", el cual
  negará por completo "wordchars".

Para obtener el mejor efecto, "punctuation_chars" debe establecerse
junto con "posix=True". (Tenga en cuenta que "posix=False" es el valor
predeterminado para "shlex".)
