Carácter delimitador menos utilizado en texto normal <ASCII 128

81

Por razones de codificación que lo horrorizarían (me da vergüenza decirlo), necesito almacenar varios elementos de texto en una sola cadena.

Los delimitaré usando un personaje.

¿Qué carácter es mejor utilizar para esto, es decir, qué carácter es menos probable que aparezca en el texto? Debe ser imprimible y probablemente menos de 128 en ASCII para evitar problemas de configuración regional.

Rahul
fuente
44
Por favor, no se avergüence. Deberías ignorar a todas las personas que dicen "oh, esa es una forma de mierda, haz esto en su lugar". No corresponde a los socorristas preguntar por qué, sino responder cómo. No me importa por qué estás en esta posición. Yo mismo he estado en algunos. ¡Buena suerte!
Iain Holder
1
Tuve el mismo problema ... y me decidí por PIPE antes de buscar en Google o desbordar la pila ... porque me gustó la forma en que se veía --- | ---- como una persona flaca.
1
Depende del tipo de texto. Algunos tipos de texto rara vez usan tabulaciones, por lo que a menudo lo uso. Pero otros tipos de texto, incluido el código fuente, a menudo lo usan. ¿No puedes hacer algunas estadísticas sobre tu texto fuente? ¿No puede agregar caracteres de escape en su texto de origen y, por lo tanto, usar lo que quiera como delimitador?
hippietrail
no preguntar y no intentar es mucho peor que avergonzarse de hacer cualquier tipo de pregunta. Estoy aquí por la respuesta de la misma pregunta y me siento orgulloso de mí mismo que tengo algunas otras personas que comparten el mismo problema conmigo :)
Teoman shipahi
Para aquellos que podrían tener un |en su texto, en realidad tuve un caso en el que necesitaba mantener los caracteres al mínimo tanto como fuera posible. Dado que la mayoría de los campos tenían cadenas con texto interesante, CSV no funcionó debido a muchos escapes. Nuestro delimitador de campo es /|. La barra es solo moderadamente común, pero junto con una tubería con la que nunca se topa. He estado usando un motor que recibe muchos datos todos los días. Esto nunca se ha roto, y nunca he necesitado encapsular una sola cadena o escapar de un carácter especial. En promedio, este mecanismo nos ha ahorrado un pequeño porcentaje de texto.
RLH

Respuestas:

34

Suponiendo que por alguna razón vergonzosa no pueda usar CSV, diría que vaya con los datos. Tome algunos datos de muestra y haga un conteo de caracteres simple para cada valor 0-127. Elija uno de los que no ocurren. Si hay demasiadas opciones, obtenga un conjunto de datos más grande. No tomará mucho tiempo escribirlo y obtendrá la mejor respuesta para usted.

La respuesta será diferente para diferentes dominios problemáticos, por lo que | (tubería) es común en los scripts de shell, ^ es común en las fórmulas matemáticas y probablemente lo mismo sea cierto para la mayoría de los demás caracteres.

Personalmente creo que apostaría por | (tubería) si tiene la opción, pero lo más seguro es ir con datos reales.

Y hagas lo que hagas, ¡asegúrate de haber elaborado un plan de escape!

Nick Fortescue
fuente
No iría a ridiculizarme aquí. En la exportación de un producto de magento 2, se combinan varios atributos en una sola columna de csv llamada additional_attributes.
Stephen
1
¿Por qué no reemplaza todos los caracteres de tabulación en el texto con cuatro espacios y usa un carácter de tabulación \tcomo delimitador?
Elie G.
35

Elegiría "Separador de unidades", código ASCII "EE. UU.": ASCII 31 (0x1F)

En los viejos tiempos, la mayoría de las cosas se hacían en serie, sin acceso aleatorio. Esto significó que algunos códigos de control se integraron en ASCII.

ASCII 28 (0x1C) File Separator - Used to indicate separation between files on a data input stream.
ASCII 29 (0x1D) Group Separator - Used to indicate separation between tables on a data input stream (called groups back then).
ASCII 30 (0x1E) Record Separator - Used to indicate separation between records within a table (within a group).  These roughly map to a tuple in modern nomenclature.
ASCII 31 (0x1F) Unit Separator - Used to indicate separation between units within a record.  The roughly map to fields in modern nomenclature.

Unit Separator está en ASCII, y hay soporte Unicode para mostrarlo (típicamente un "nosotros" en el mismo glifo) pero muchas fuentes no lo muestran.

Si debe mostrarlo, le recomendaría que lo muestre en la aplicación, después de analizarlo en campos.

Edwin Buck
fuente
1
Wow gracias. esto era exactamente lo que estaba buscando.
Theunis
22

Probablemente | o ^ o ~ también puedes combinar dos caracteres

SQLMenace
fuente
10
usar dos veces lo mismo evitará cualquier malentendido. Me gusta || o ##
roel
17

Cuando se utilizan diferentes idiomas, este símbolo: ¬

demostró ser el mejor. Sin embargo, todavía estoy probando.

Icarin
fuente
1
Me gusta esta idea, pero tengo curiosidad por saber si puedes archivar cadenas que contengan cadenas como "Billy" ¬ "Coche" ¬ "Rojo" ¬ "Garaje" ¬ "3" y usar cortar. (es decir, $ cut -d "¬" -f1 myfile.delim)
blehman
Agregué
15

Dijiste "imprimible", pero eso puede incluir caracteres como una pestaña (0x09) o un avance de formulario (0x0c). Casi siempre elijo pestañas en lugar de comas para los archivos delimitados, ya que a veces pueden aparecer comas en el texto.

(Curiosamente, la tabla ascii tiene los caracteres GS (0x1D), RS (0x1E) y US (0x1F) para separadores de grupos, registros y unidades, sean cuales sean / fueron).

Si por "imprimible" te refieres a un carácter que un usuario pueda reconocer y escribir fácilmente, optaría por la tubería | símbolo en primer lugar, con algunos otros caracteres extraños ( @o ~, o ^, o \, o de acento grave que no puedo parecer para entrar aquí) como una posibilidad. +=!$%&*()-'":;<>,.?/Parece que es más probable que estos caracteres aparezcan en la entrada del usuario. En cuanto al subrayado, el _hash #y los corchetes {}[], no lo sé.

Jason S
fuente
14
La tabla de códigos ASCII estándar incluye cuatro códigos de control diseñados específicamente para este propósito, como lo mencionó Jason S anteriormente. Ellos son: 28 FSSeparador de archivos, Separador de 29 GSgrupos, 30 RSSeparador de registros, 31 USSeparador de unidades. Desafortunadamente, casi nadie los usa, aunque eso es exactamente para lo que fueron diseñados. Personalmente, detesto los archivos en formato CSV porque muchas personas no piensan bien las cosas y crean un lío con el que los programadores tenemos que lidiar si queremos admitir sus formatos de archivo.
deegee
3
@deegee, esta es probablemente la mejor respuesta aquí. A menos que los datos contengan ascii / unicode binarios o no estándar, esto siempre funcionará en cualquier idioma. Deberías convertir esto en una respuesta regular.
dhj
@rahul, ¿tienes los poderes para marcar esto como la respuesta aceptada? Más útil cuando se trata de datos de entrada de usuario llenos de basura. Nota para los demás: ALT + 31 para obtener US (0x1F) en Windows.
golfalot
14

¿Qué tal si usa un formato de estilo CSV? Los caracteres se pueden escapar en un formato CSV estándar, y ya hay muchos analizadores escritos.

Alex Fort
fuente
Me gusta esto más que mi idea. +1.
Iain Holder
Creo que una coma cuenta como carácter común en un texto normal. Si fuera tan simple como usar CSV, dudo que sea necesario hacer la pregunta ...
Jay
csv se ocupa de las comas en el texto normal, así como de algunos otros problemas. Así que no importa que ya haya una coma en el texto. IIRC pone el texto entre comillas y escapa a las comillas.
Jeremy French
@Jeremy: exactamente correcto. Aquí hay un artículo de Wikipedia que menciona cómo funciona el esquema de escape: en.wikipedia.org/wiki/Comma-separated_values
rmeador
1
Para decirlo sin rodeos: CVS se ocupará de todos esos problemas en los que no pensó y se asegurará de que no tenga que arreglar su "solución" cada dos semanas porque se rompe debido a alguna entrada imprevista.
Aaron Digulla
9

¿Puedes usar un símbolo de tubería? Ese suele ser el siguiente delimitador más común después de las cadenas delimitadas por comas o tabulaciones. Es poco probable que la mayoría del texto contenga una tubería, y ord ('|') devuelve 124 para mí, por lo que parece ajustarse a sus requisitos.

Arrendajo
fuente
8

Para escapar rápidamente, uso cosas como esta: digamos que desea concatinar str1, str2 y str3, lo que hago es:

delimitedStr=str1.Replace("@","@a").Replace("|","@p")+"|"+str2.Replace("@","@a").Replace("|","@p")+"|"+str3.Replace("@","@a").Replace("|","@p");

luego para recuperar el uso original:

splitStr=delimitedStr.Split("|".ToCharArray());
str1=splitStr[0].Replace("@p","|").Replace("@a","@");
str2=splitStr[1].Replace("@p","|").Replace("@a","@");
str3=splitStr[2].Replace("@p","|").Replace("@a","@");

nota: el orden de reemplazo es importante

es irrompible y fácil de implementar

Mohammad Amin
fuente
2
Esta es realmente la mejor respuesta aquí, y la única correcta en mi opinión. Es la única respuesta que no se puede romper. Todas las demás respuestas solo reducen la probabilidad de que la entrada rompa el formato, pero este es un enfoque muy, muy pobre. La respuesta seleccionada habla correctamente de usar un esquema de escape como este, pero una vez que lo hace, la elección del delimitador es esencialmente irrelevante.
Alfie
El delimitador no es del todo irrelevante. Si elige un carácter común, digamos un espacio o la letra "e", su cadena de escape se volverá bastante larga y difícil de leer. Es mejor elegir un personaje poco común, por eso sigo prefiriendo el símbolo de la tubería para este tipo de cosas.
fool4jesus
2

¡Pipe para la victoria! |

Eppz
fuente
2

Usamos ascii 0x7f, que es pseudoimprimible y casi nunca aparece en el uso regular.

Joe
fuente
2

Esto puede ser bueno o malo (generalmente malo) dependiendo de la situación y el idioma, pero tenga en cuenta que siempre puede codificar todo en Base64. Entonces no tiene que preocuparse por escapar y eliminar varios patrones en cada lado, y simplemente puede separar y dividir cadenas según un carácter que no se usa en su juego de caracteres Base64.

He tenido que recurrir a esta solución cuando me he enfrentado a poner documentos XML en propiedades / nodos XML. Las propiedades no pueden tener bloques CDATA en absoluto, y los nodos escapados como CDATA obviamente no pueden tener más bloques CDATA dentro sin romper la estructura.

Sin embargo, CSV es probablemente una mejor idea para la mayoría de las situaciones.

Seguro en sí mismo
fuente
La codificación base64 es una solución simple, sin embargo, la razón principal por la que se usa CSV es porque no tiene que volver a analizar el texto, al usar base64 también podría inventar su propio formato por completo.
llega el
1

Bueno, va a depender de la naturaleza de su texto hasta cierto punto, pero una barra vertical 0x7C no aparece en el texto muy a menudo.

Jackson
fuente
1

No creo que haya visto nunca un ampersand seguido de una coma en texto natural, pero primero puede verificar el archivo para ver si contiene el delimitador y, de ser así, usar una alternativa. Si desea saber siempre que el delimitador que usa no causará un conflicto, haga un bucle verificando el archivo en busca del delimitador que desea, y si existe, duplique la cadena hasta que el archivo ya no tenga una coincidencia. . No importa si hay cadenas similares porque su programa solo buscará coincidencias exactas del delimitador.


fuente
1

Tanto la tubería como el cursor son las opciones obvias. Me gustaría señalar que si se espera que los usuarios escriban la respuesta completa, el signo de intercalación es más fácil de encontrar en cualquier teclado que la tubería.

Will Johnson
fuente