separar - string to array c#
¿Qué es un delimitador más exclusivo que la coma para separar cadenas? (21)
¿El usuario ingresará cadenas delimitadas en los cuadros de texto o ingresará cadenas individuales que luego se integrarán en las cadenas delimitadas por su código?
En el primer caso, podría ser mejor replantearse la interfaz de usuario. por ejemplo, el usuario podría ingresar una cadena a la vez en un cuadro de texto y hacer clic en el botón "Agregar a la lista" después de cada una.
En el segundo caso, realmente no importa qué delimitador utilice. Elige cualquier personaje que te guste, solo asegúrate de escapar de cualquier otra aparición de ese personaje.
EDITAR
Dado que varios comentarios sobre otras respuestas están pidiendo código, aquí hay un método para crear una cadena delimitada por comas, utilizando la barra invertida como el carácter de escape:
public static string CreateDelimitedString(IEnumerable<string> items)
{
StringBuilder sb = new StringBuilder();
foreach (string item in items)
{
sb.Append(item.Replace("//", "////").Replace(",", "//,"));
sb.Append(",");
}
return (sb.Length > 0) ? sb.ToString(0, sb.Length - 1) : string.Empty;
}
Y aquí está el método para convertir esa cadena delimitada por comas de nuevo a una colección de cadenas individuales:
public static IEnumerable<string> GetItemsFromDelimitedString(string s)
{
bool escaped = false;
StringBuilder sb = new StringBuilder();
foreach (char c in s)
{
if ((c == ''//') && !escaped)
{
escaped = true;
}
else if ((c == '','') && !escaped)
{
yield return sb.ToString();
sb.Remove(0, sb.Length);
}
else
{
sb.Append(c);
escaped = false;
}
}
yield return sb.ToString();
}
Y aquí hay algunos ejemplos de uso:
string[] test =
{
"no commas or backslashes",
"just one, comma",
@"a comma, and a/ backslash",
@"lots, of/ commas,/ and/, backslashes",
@"even// more,, commas// and,, backslashes"
};
string delimited = CreateDelimitedString(test);
Console.WriteLine(delimited);
foreach (string item in GetItemsFromDelimitedString(delimited))
{
Console.WriteLine(item);
}
Tengo varios cuadros de texto donde los usuarios pueden ingresar información en ellos. Esto puede incluir comas, por lo que no puedo usar las cadenas delimitadas por comas estándar.
¿Cuál es un buen delimitador para indicar que las cadenas deben separarse en función de ese carácter que los usuarios no suelen utilizar en sus escritos? Voy a combinar estos campos en una cadena de caracteres y pasarlos a mi método de cifrado que tengo. Después de descifrarlos necesito poder separarlos de manera confiable.
Estoy usando C # si importa.
¿Nueva línea? (es decir, utilizar un cuadro de texto multilínea)
¿Por qué no simplemente envuelve cada entrada entre comillas?
De esa manera terminas con esto:
"Aaron","Johnson","25","I like cats, and dogs"
No te olvides de escapar de las citas en la entrada ...
Como se ha señalado, cualquier personaje que elija tiene la posibilidad de aparecer en la entrada, por lo que tiene que manejar el escape. XML puede ser un buen formato de serialización para usar, ya que creo que .NET tiene un buen soporte para la creación y eliminación de XML. Es probable que esto sea mucho más sólido que tratar de implementar su propio escape de personaje, y también será más extensible en el futuro.
Cualquiera de los caracteres no estándar pipe |, backtick `, tilde ~, bang!, O punto y coma; probablemente funcionaria Sin embargo, si sigues esta ruta, realmente te estás aventurando lejos de la usabilidad. Pedirles que escapen de comas con una barra invertida o algo les ruega que se los pierdan.
Si CSV no es posible, entonces debería considerar cambiar su interfaz de usuario. (¡Caramba, deberías mantenerte alejado del CSV de todos modos para una entrada del usuario!) Dices "cuadro de texto", así que asumo que estás en la web o en algún tipo de formularios de ganancia o WPF (definitivamente no es una consola). Todos estos le brindan un mejor control de la UI que un solo cuadro de texto y obligan a los usuarios a ajustarse a su difícil diseño de UI.
Más información definitivamente ayudaría a guiar mejor las respuestas.
Sin embargo, como un ejemplo de escapar de una coma con una barra invertida. Tenga en cuenta que no puede escapar de la barra diagonal inversa antes de una coma con esto. Así que @ "uno, dos, tr //, es" terminará con {"uno", "dos", "tr / es"}.
string data = @"uno, dos, tr/,es";
string[] items = data.Split('',''); // {"uno", " dos", @"tr/", "es"}
List<string> realitems = new List<string>();
for (int i=items.Length-1; i >= 0; i--)
{
string item = items[i];
if (item.Length == 0) { realitems.Insert(0, ""); continue; }
if (realitems.Count == 0) { realitems.Insert(0, item); }
else
{
if (item[item.Length - 1] == ''//') { realitems[0] = item + "," + realitems[0]; }
else { realitems.Insert(0, item); }
}
}
// Should end up with {"uno", " dos", "tr,es"}
Detecta un carácter que no se usa, y luego usa eso. Su cadena final combinada puede comenzar con el carácter que debe ser de ese punto utilizado como delimitador.
Ejemplo: sus usuarios ingresan "pants" ",;,;,;,;,;" y "| ~~ |" Recorrerá un conjunto de caracteres hasta que encuentre uno que no se usa. Podría ser, digamos, "$" Su cadena final, concatenada, entonces, es "$ pants $,;,;,;,,,, $ | ~~ |" El carácter inicial le dice a su programa qué carácter se utilizará como delimitador. De esta manera, no hay caracteres prohibidos, punto.
El backtick. Nadie usa el backtick.
El personaje de la tubería (|), tal vez? Si su base de usuarios es tímido de forma remota por TI, entonces este enfoque (pidiéndoles que delimite su texto) podría no ser el mejor; podría intentar otra cosa, por ejemplo, proporcionar algunos medios para agregar dinámicamente un cuadro de texto sobre la marcha que acepte otra cadena, etc.
Si proporciona un poco más de información sobre lo que está haciendo y para quién, es posible que alguien sugiera un enfoque alternativo.
He visto caracteres no utilizados como delimitadores, incluso combinaciones de caracteres poco comunes como -|::|-
, pero aunque es más improbable que ocurran, todavía pueden.
Básicamente tienes dos opciones si quieres que sea hermético:
1: use un carácter que es imposible de escribir, como el carácter ''/ 0'':
Unirse:
string combined = string.Join("/0", inputArray);
División:
string[] result = combined.Split(''/0'');
2: Escape de la cadena y use un carácter de escape como delimitador, como la url que codifica los valores y use & como delimitador:
Unirse:
string combined = string.Join("&", inputArray.Select<string,string>(System.Web.HttpUtility.UrlEncode).ToArray());
División:
string[] result = combined.Split(''&'').Select<string,string>(System.Web.HttpUtility.UrlDecode).ToArray();
La mejor solución es seguir las comas e introducir el soporte para el escape de personajes. Cualquier carácter que seleccione eventualmente deberá ingresarse para que también pueda brindar apoyo para esto.
Piense backslases + comillas dobles dentro de cadenas entre comillas dobles.
No escoja un carácter como comilla invertida porque algunos usuarios pueden no saber cómo escribirlo ...
Mark Brackett tiene la respuesta correcta. Solo agregaré que el mismo número de respuestas a esta simple pregunta debería dejar de usar cadenas delimitadas, siempre. Que esto sea una "palabra para los sabios".
Me imagino que eventualmente, cada personaje va a ser usado por alguien. Los usuarios siempre encuentran una manera de romper nuestro analizador HL7.
En lugar de un solo carácter, tal vez intente una cadena que sea lo suficientemente aleatoria para que nadie la use. Algo como "#!@!#".
Nadie dijo TAB? La pestaña delimitada es excelente, pero no es fácil escribir pestañas en las GUI (tiende a pasar al siguiente elemento de la pantalla). Pero para archivos generados por computadora, TAB es perfecto, ya que nunca debería aparecer en el texto generado por el usuario.
No creo que voluntariamente haya delimitado una colección de cadenas desde que dejé de usar C. Simplemente no hay necesidad de hacerlo en un lenguaje "moderno" y, aunque trivial, la cantidad de casos de borde es suficiente para molestarlo. a muerte.
Almacénelos en una Lista <string> o cadena [] y serialícelos / deserializarlos. Use XML si quiere legibilidad humana o interoperabilidad, o binario serialice si no lo hace. Puede cifrar la salida fácilmente de cualquier manera, y no hay ambigüedad o crear sus propias rutinas de escape necesarias.
En C #, es menos LOC y toma menos tiempo para escribir que esta respuesta. No hay excusa para rodar tu propia solución.
Prefiero usar una combinación de caracteres a los que una persona normal no ingresaría como mi delimitador cuando sea posible. Por ejemplo, he usado ") ^ & ^ (" y lo configuré como una constante "cDelimiter" en mi código; luego concatené todos mis campos con eso. Al usar una cadena única y pequeña, reduzco considerablemente la probabilidad de que aparezca del usuario que ingresa accidentalmente mi delimitador. El capó probable de un usuario que ingresa un | o un ~ es ciertamente improbable, pero no significa que no sucederá.
Sé que esta respuesta es bastante tardía, pero experimenté este problema hace un tiempo y la abordé razonablemente bien (IMHO). Con suerte, en el futuro, esto ayudará a alguien más a buscar una respuesta a una pregunta similar.
Si bien generalmente me ubicaría en campamentos similares a Mike Ottum, John Saunders y Mark Brackett, el simple hecho del asunto es que a veces los desarrolladores tenemos que hacer cosas que preferimos no hacer. Mi caso particular tenía la necesidad de proporcionar una "identificación" legible por humanos (en su mayoría) para usar en un URI RESTful derivado de una clave compuesta orgánica de un objeto. La serialización binaria o XML no era realmente una opción. ¿Asi que? Elegí reinventar lo menos posible de la rueda. La clase System.Text.RegularExpressions.Regex tiene métodos de escape / unescape que operan en esos patrones regex locos. Hay un puñado de caracteres escapables para elegir. Me instalé en la pipa (''|'') carácter.
Aquí estaba mi implementación (si se usara la clase para reutilizarla, pero podrías sacar los buenos bits para una solución "en línea" de 7 líneas si así es como te gustaría rodar):
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace RPlus.DTO
{
/// <summary>
/// Provide safe string un/concatenating
/// </summary>
static class Glob
{
// a Regex Split param that basically says:
// Split on the pipe char unless the preceeding char is a backslash
private const string _splitterer = @"(?<!//)/|";
// no explanation needed (hopefully)
private const char _delimiter = ''|'';
/// <summary>
/// Produce a properly escaped concatenation
/// from some number of strings
/// </summary>
/// <param name="items">strings to escape/concate</param>
/// <returns>an escaped concatenation of items</returns>
public static string To(IEnumerable<string> items)
{
var escapedItems = new List<string>();
foreach (var s in items) escapedItems.Add(Regex.Escape(s));
return string.Join(_delimiter.ToString(), escapedItems);
}
/// <summary>
/// Unconcatenate/unescape a string into its original strings
/// </summary>
/// <param name="globbedValue">
/// A value returned from Glob.To()
/// </param>
/// <returns>
/// The orignal strings used to construct the globbedValue
/// </returns>
public static List<string> From(string globbedValue)
{
return From(globbedValue, default(int?));
}
/// <summary>
/// Unconcatenate/unescape a string into its original strings
/// </summary>
/// <param name="globbedValue">
/// A value returned from Glob.To()
/// </param>
/// <param name="expectedTokens">
/// The number of string tokens that
/// should be found in the concatenation
/// </param>
/// <returns>
/// The orignal strings used to construct the globbedValue
/// </returns>
public static List<string> From(string value, int? expectedTokens)
{
var nugs = Regex.Split(value, _splitterer);
if (expectedTokens.HasValue && nugs.Length != expectedTokens.Value)
throw new ArgumentException("Unexpected number of tokens");
var unescapedItems = new List<string>();
foreach (var s in nugs) unescapedItems.Add(Regex.Unescape(s));
return unescapedItems;
}
}
}
Y aquí hay algunos ejemplos de uso:
var glob = Glob.To(new string[] { "Foo|Bar", "Bar|Baz", "Baz|Qux" });
var orig = Glob.From(glob);
AVISO: no intente encontrar "un carácter que los usuarios nunca ingresen" para usarlo como un delimitador de cadenas concatenadas. Los usuarios finalmente lo ingresarán. Ya hay suficiente código de "número mágico" esperando explotar. Y hay múltiples soluciones probadas y probadas para el problema.
Sugeriría usar ";"
Supongo que por lo que dice que el usuario está ingresando datos en campos separados, y luego los está combinando. Por lo tanto, el usuario nunca necesita saber o preocuparse por el delimitador.
No solo intentes elegir un personaje que "nadie usa", ya sea por accidente o para intentar romper tu código, algún usuario lo usará eventualmente.
Entonces, yo:
Inserte barras diagonales inversas para evitar comas y barras diagonales inversas en la entrada del usuario, luego combine las cadenas con comas. Para separar, se divide en comas no escapadas (que es un trabajo para una máquina de estado), luego se sale de cada componente.
Utilice un medio comercial para serializar una lista de cadenas. Lo que está disponible depende de su entorno, no conozco a C # / .NET lo suficientemente bien como para asesorarlo. En Java puedes simplemente serializar un vector o lo que sea.
Separe los datos con un carácter de control como ASCII-BEL o ASCII-VT (o ASCII-NUL si sus cadenas nunca se tratan como terminadas en nulo), y rechace las entradas del usuario que contengan ese carácter.
La primera opción es buena si el usuario debe poder ingresar cualquier valor char que desee. La segunda opción es buena si no le importa inflar los datos de manera significativa. La tercera opción es buena si no le importa rechazar a los usuarios de smart-alec (o aquellos con requisitos inusuales) que intentan insertar datos divertidos.
También apoyo la selección de TAB (/ t) y, hasta cierto punto, el símbolo PIPE (|).
Pero el más usado en mi experiencia es el punto y coma (;) junto con los campos entre comillas y los escapes para / y / "que es simplemente perfecto. Solo necesita un analizador que mantenga el estado. La delimitación real no es importante.
Si no utiliza ningún escape, es aconsejable contar los "campos" por línea y compararlos con los resultados esperados. Como la mayoría de las aplicaciones de este tipo de archivos utilizan algún tipo de número fijo de campos, puede detectar errores en la entrada y lograr que todo se sienta bien si no se activa.
Use una pestaña (o tal vez / n), que si es ingresada por el usuario causará que se cierre el cuadro de texto.
| sería el siguiente en mi lista y se usa a menudo como alternativa al CSV. google "delimitado por tuberías" y encontrarás muchos ejemplos.
string[] items = new string[] {"Uno","Dos","Tres"};
string toEncrypt = String.Join("|", items);
items = toEncrypt.Split(new char[] {''|''}, StringSplitOptions.RemoveEmptyEntries);
foreach(string s in items)
Console.WriteLine(s);
Y dado que a todos les gusta ser críticos acerca de la codificación y no proporcionar el código, aquí hay una forma de codificar el texto para que su | Delim no chocará.
string[] items = new string[] {"Uno","Dos","Tres"};
for (int i = 0; i < items.Length; i++)
items[i] = Convert.ToBase64String(Encoding.UTF8.GetBytes(items[i]));
string toEncrypt = String.Join("|", items);
items = toEncrypt.Split(new char[] {''|''}, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in items)
Console.WriteLine(Encoding.UTF8.GetString(Convert.FromBase64String(s)));