Je voudrais convertir une chaîne contenant une gamme récursive de chaînes en une éventail de profondeur une.
Exemple: P>
StringToArray("[a, b, [c, [d, e]], f, [g, h], i]") == ["a", "b", "[c, [d, e]]", "f", "[g, h]", "i"]
5 Réponses :
Honnêtement, je voudrais simplement écrire cette méthode dans une assemblée F # comme il est probablement beaucoup plus facile. Si vous regardez la mise en œuvre code> JavasCriPtSerializer CODE> en C # (avec un décompiler comme DotPek ou un réflecteur), vous pouvez voir à quel point le code d'analyse de la matrice désordonnée est désordonné pour un tableau similaire dans JSON. Accordé cela doit gérer une gamme beaucoup plus variée de jetons, mais vous obtenez l'idée.
Voici leur implémentation désériializelist code> Normalement comme la version décompilée de sa DotPeek, pas l'original, pas l'original, pas l'original, Mais vous avez l'idée. Le désériializeinternal code> se recueille à la liste des enfants. P> private IList DeserializeList(int depth)
{
IList list = (IList) new ArrayList();
char? nullable1 = this._s.MoveNext();
if (((int) nullable1.GetValueOrDefault() != 91 ? 1 : (!nullable1.HasValue ? 1 : 0)) != 0)
throw new ArgumentException(this._s.GetDebugString(AtlasWeb.JSON_InvalidArrayStart));
bool flag = false;
char? nextNonEmptyChar;
char? nullable2;
do
{
char? nullable3 = nextNonEmptyChar = this._s.GetNextNonEmptyChar();
if ((nullable3.HasValue ? new int?((int) nullable3.GetValueOrDefault()) : new int?()).HasValue)
{
char? nullable4 = nextNonEmptyChar;
if (((int) nullable4.GetValueOrDefault() != 93 ? 1 : (!nullable4.HasValue ? 1 : 0)) != 0)
{
this._s.MovePrev();
object obj = this.DeserializeInternal(depth);
list.Add(obj);
flag = false;
nextNonEmptyChar = this._s.GetNextNonEmptyChar();
char? nullable5 = nextNonEmptyChar;
if (((int) nullable5.GetValueOrDefault() != 93 ? 0 : (nullable5.HasValue ? 1 : 0)) == 0)
{
flag = true;
nullable2 = nextNonEmptyChar;
}
else
goto label_8;
}
else
goto label_8;
}
else
goto label_8;
}
while (((int) nullable2.GetValueOrDefault() != 44 ? 1 : (!nullable2.HasValue ? 1 : 0)) == 0);
throw new ArgumentException(this._s.GetDebugString(AtlasWeb.JSON_InvalidArrayExpectComma));
label_8:
if (flag)
throw new ArgumentException(this._s.GetDebugString(AtlasWeb.JSON_InvalidArrayExtraComma));
char? nullable6 = nextNonEmptyChar;
if (((int) nullable6.GetValueOrDefault() != 93 ? 1 : (!nullable6.HasValue ? 1 : 0)) != 0)
throw new ArgumentException(this._s.GetDebugString(AtlasWeb.JSON_InvalidArrayEnd));
else
return list;
}
Il n'y a pas de véritable moyen "standard" de faire cela. Notez que la mise en œuvre peut devenir assez désordonnée si vous souhaitez envisager toutes les possibilités. Je recommanderais quelque chose de récursif comme:
private static IEnumerable<object> StringToArray1(string input)
{
Stack<List<object>> levelEntries = new Stack<List<object>>();
List<object> current = null;
StringBuilder currentLineBuilder = new StringBuilder();
foreach (char nextChar in input)
{
switch (nextChar)
{
case '[':
levelEntries.Push(current);
current = new List<object>();
break;
case ']':
current.Add(currentLineBuilder.ToString());
currentLineBuilder.Clear();
var last = current;
if (levelEntries.Peek() != null)
{
current = levelEntries.Pop();
current.Add(last);
}
break;
case ',':
current.Add(currentLineBuilder.ToString());
currentLineBuilder.Clear();
break;
default:
currentLineBuilder.Append(nextChar);
break;
}
}
return current;
}
avec regex, il peut résoudre votre problème:
Je pense aussi que Regex est la voie à suivre, mais cela ne fonctionnera pas, car vous devez capturer des accolades «équilibrées».
@Scottrippey Bonjour, Scott, j'ai modifié mon code, essayez s'il vous plaît.
Ça à l'air bon. Besoin d'un peu de nettoyage, mais je suppose que cela fonctionne :) Pour toute autre personne intéressée par ces "groupes d'équilibrage", en particulier pour une correspondance équilibrée, vous devez consulter Documentation de Microsoft sur" Équilibrer les définitions de groupe ".
using System;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic.FileIO; //Microsoft.VisualBasic.dll
using System.IO;
public class Sample {
static void Main(){
string data = "[a, b, [c, [d, e]], f, [g, h], i]";
string[] fields = StringToArray(data);
//check print
foreach(var item in fields){
Console.WriteLine("\"{0}\"",item);
}
}
static string[] StringToArray(string data){
string[] fields = null;
Regex innerPat = new Regex(@"\[\s*(.+)\s*\]");
string innerStr = innerPat.Matches(data)[0].Groups[1].Value;
StringBuilder wk = new StringBuilder();
var balance = 0;
for(var i = 0;i<innerStr.Length;++i){
char ch = innerStr[i];
switch(ch){
case '[':
if(balance == 0){
wk.Append('"');
}
wk.Append(ch);
++balance;
continue;
case ']':
wk.Append(ch);
--balance;
if(balance == 0){
wk.Append('"');
}
continue;
default:
wk.Append(ch);
break;
}
}
var reader = new StringReader(wk.ToString());
using(var csvReader = new TextFieldParser(reader)){
csvReader.SetDelimiters(new string[] {","});
csvReader.HasFieldsEnclosedInQuotes = true;
fields = csvReader.ReadFields();
}
return fields;
}
}
@OJLOVECD a une bonne réponse, en utilisant des expressions régulières. Utilisation de ce code, vous verrez que Pour plus d'informations sur les groupes équilibrés que j'ai utilisés pour assortir des accolades équilibrées, jetez un coup d'œil à la documentation de Microsoft . p>
Cependant, sa réponse est trop compliquée, alors voici ma réponse similaire simple. stringtoarray ("[A, B, [C, [ d, e]], f, [g, h], i] ") code> retournera le tableau suivant: [" A "," B "," [C, [D, E]] "," F "," [G, H] "," I "] CODE>. P>
Selon les commentaires, si vous souhaitez également équilibrer des citations, voici une modification possible. (Notez que dans C # le " code> est échappé comme " " code>) J'ai également ajouté des descriptions du motif pour l'aider à clarifier: p> var pattern = new Regex(@"
\[
(?:
\s*
(?<results>(?: # Capture everything into 'results'
(?(open) # If 'open' Then
[^\[\]]+ # Capture everything but brackets
| # Else (not open):
(?: # Capture either:
[^\[\],'""]+ # Unimportant characters
| # Or
['""][^'""]*?['""] # Anything between quotes
)
) # End If
|(?<open>\[) # Open bracket
|(?<-open>\]) # Close bracket
)+)
(?(open)(?!)) # Fail while there's an unbalanced 'open'
,?
)*
\]
", RegexOptions.IgnorePatternWhitespace);
C'est une solution fantastique. :)
Merci, j'espère que je n'ai pas volé ton tonnerre :)
Certainement pas. Il n'y a qu'une discussion et une amélioration. :)
Votre solution est belle. J'ai finalement réussi à trouver le temps et à l'étudier, et c'est vraiment fantastique. Seulement un problème: maintenant je voudrais que les chaînes soient également préservées comme des entités atomiques, même si elles contiennent des listes (donc: "[A, \" B, [C, D] \ ", E]" => ["A" , "B, [C, D]", "E"]]), mais les citations n'ont pas de distinction entre l'ouverture et la clôture de citation, de sorte que les groupes d'équilibrage ne fonctionnent pas. Avez-vous une solution élégante à cela aussi? :-)
Citations équilibrées - moyen de lancer une clé dans le moteur! Je l'ai fait en JavaScript récemment , mais cette solution utilisait RegEx comme un moteur analysant, donc ce n'était donc pas une solution pure regex. Il pourrait être intéressant de jeter un coup d'œil.
J'ai ajouté à ma réponse ma tentative de citations équilibrées.
+1 pour un problème difficile. Cependant, je pense que c'est généralement pour Codereview: codereview.stackexchange.com/faq#questions.