2016-07-31 28 views
2

Sagen wir, ich habe eine string wie diese, der linke Teil ist ein Wort, der rechte Teil ist eine Sammlung von Indizes (single oder range) zur Referenz furigana (Phonetik) für kanjis in meinem Wort:C# Wie erstelle ich eine neue Zeichenfolge basierend auf multiple Entfernungsindex

string myString = "子で子にならぬ時鳥,0:こ;2:こ;7-8:ほととぎす" 

Das Muster im Detail:

word,<startIndex>(-<endIndex>):<furigana> 

Was wäre der beste Weg, so etwas wie dieses (mit einem Raum vor dem Kanji zu erreichen, welcher Teil zu markieren ist verbunden mit [Furigana]):

子[こ]で 子[こ]にならぬ 時鳥[ほととぎす] 

bearbeiten: (Danke für Ihre Kommentare Männer)

Hier ist, was ich bisher geschrieben:

static void Main(string[] args) 
     { 
      string myString = "ABCDEF,1:test;3:test2"; 

      //Split Kanjis/Indices 
      string[] tokens = myString.Split(','); 

      //Extract furigana indices 
      string[] indices = tokens[1].Split(';'); 

      //Dictionnary to store furigana indices 
      Dictionary<string, string> furiganaIndices = new Dictionary<string, string>(); 

      //Collect 
      foreach (string index in indices) 
      { 
       string[] splitIndex = index.Split(':'); 
       furiganaIndices.Add(splitIndex[0], splitIndex[1]); 
      } 

      //Processing 
      string result = tokens[0] + ","; 

      for (int i = 0; i < tokens[0].Length; i++) 
      { 
       string currentIndex = i.ToString(); 

       if (furiganaIndices.ContainsKey(currentIndex)) //add [furigana] 
       { 
        string currentFurigana = furiganaIndices[currentIndex].ToString(); 
        result = result + " " + tokens[0].ElementAt(i) + string.Format("[{0}]", currentFurigana); 
       } 
       else //nothing to add 
       { 
        result = result + tokens[0].ElementAt(i); 
       } 
      } 

      File.AppendAllText(@"D:\test.txt", result + Environment.NewLine); 
     } 

Ergebnis:

ABCDEF,A B[test]C D[test2]EF 

Ich kämpfe ein finden Weg zur Verarbeitung von Entfernungsindizes:

string myString = "ABCDEF,1:test;2-3:test2"; 
Result : ABCDEF,A B[test] CD[test2]EF 
+2

Können Sie bitte ein Beispiel mit nur alphanumerischen Zeichen erstellen? Außerdem sollten Sie Ihren Versuch teilen, den Code, den Sie versucht haben, usw. – MarcinJuraszek

+0

Ein [kurzes, eigenständiges und korrektes (kompilierbares) Beispiel] (http://sscce.org/) würde helfen zu klären, was Sie immens zu tun versuchen. –

Antwort

1

Ich habe nichts gegen manuell zu manipulieren Strings per se. Aber da Sie ein regelmäßiges Muster zu haben scheinen, das die Eingaben beschreibt, scheint mir, dass eine Lösung, die Regex verwendet, wartungsfreundlicher und lesbarer wäre. Also in diesem Sinne, hier ist ein Beispielprogramm, das diesen Ansatz nimmt:

class Program 
{ 
    private const string _kinvalidFormatException = "Invalid format for edit specification"; 

    private static readonly Regex 
     regex1 = new Regex(@"(?<word>[^,]+),(?<edit>(?:\d+)(?:-(?:\d+))?:(?:[^;]+);?)+", RegexOptions.Compiled), 
     regex2 = new Regex(@"(?<start>\d+)(?:-(?<end>\d+))?:(?<furigana>[^;]+);?", RegexOptions.Compiled); 

    static void Main(string[] args) 
    { 
     string myString = "子で子にならぬ時鳥,0:こ;2:こ;7-8:ほととぎす"; 
     string result = EditString(myString); 
    } 

    private static string EditString(string myString) 
    { 
     Match editsMatch = regex1.Match(myString); 

     if (!editsMatch.Success) 
     { 
      throw new ArgumentException(_kinvalidFormatException); 
     } 

     int ichCur = 0; 
     string input = editsMatch.Groups["word"].Value; 
     StringBuilder text = new StringBuilder(); 

     foreach (Capture capture in editsMatch.Groups["edit"].Captures) 
     { 
      Match oneEditMatch = regex2.Match(capture.Value); 

      if (!oneEditMatch.Success) 
      { 
       throw new ArgumentException(_kinvalidFormatException); 
      } 

      int start, end; 

      if (!int.TryParse(oneEditMatch.Groups["start"].Value, out start)) 
      { 
       throw new ArgumentException(_kinvalidFormatException); 
      } 

      Group endGroup = oneEditMatch.Groups["end"]; 

      if (endGroup.Success) 
      { 
       if (!int.TryParse(endGroup.Value, out end)) 
       { 
        throw new ArgumentException(_kinvalidFormatException); 
       } 
      } 
      else 
      { 
       end = start; 
      } 

      text.Append(input.Substring(ichCur, start - ichCur)); 
      if (text.Length > 0) 
      { 
       text.Append(' '); 
      } 
      ichCur = end + 1; 
      text.Append(input.Substring(start, ichCur - start)); 
      text.Append(string.Format("[{0}]", oneEditMatch.Groups["furigana"])); 
     } 

     if (ichCur < input.Length) 
     { 
      text.Append(input.Substring(ichCur)); 
     } 

     return text.ToString(); 
    } 
} 

Hinweise:

  • Diese Implementierung wird davon ausgegangen, dass die Bearbeitungs Spezifikationen werden aufgelistet, um und werden nicht überlappen. Es wird nicht versucht, diesen Teil der Eingabe zu validieren; Abhängig davon, woher du deine Eingabe bekommst, möchtest du vielleicht hinzufügen. Wenn es zulässig ist, dass die Spezifikationen nicht in der Reihenfolge aufgeführt werden, können Sie das oben genannte auch so erweitern, dass zuerst die Änderungen in einer Liste gespeichert und die Liste nach dem Startindex sortiert wird, bevor die Zeichenfolge tatsächlich bearbeitet wird. (In ähnlicher Weise wie die andere vorgeschlagene Antwort funktioniert; obwohl, warum sie ein Wörterbuch anstelle einer einfachen Liste verwenden, um die einzelnen Änderungen zu speichern, habe ich keine Ahnung & hellip; das scheint willkürlich kompliziert.)
  • ich aufgenommen Grundlegende Eingabeüberprüfung, wobei Ausnahmen ausgelöst werden, bei denen Fehler beim Musterabgleich auftreten. Eine benutzerfreundlichere Implementierung würde spezifischere Informationen zu jeder Ausnahme hinzufügen und beschreiben, welcher Teil der Eingabe tatsächlich ungültig war.
  • Die Regex Klasse hat tatsächlich eine Replace() Methode, die eine vollständige Anpassung ermöglicht. Das obige könnte so implementiert worden sein, unter Verwendung von Replace() und MatchEvaluator, um den Ersetzungstext zur Verfügung zu stellen, anstatt nur Text an eine StringBuilder anzufügen. Welcher Weg es zu tun ist, ist meistens eine Frage der Präferenz, obwohl die MatchEvaluator bevorzugt werden könnte, wenn Sie flexiblere Implementierungsoptionen benötigen (d. H. Wenn das genaue Format des Ergebnisses variieren kann).
  • Wenn Sie sich entscheiden, die andere vorgeschlagene Antwort zu verwenden, empfehle ich Ihnen dringend StringBuilder statt einfach auf die results Variable zu verketten. Für kurze Strings spielt es keine Rolle, aber Sie sollten sich die Angewohnheit immer mit StringBuilder aneignen, wenn Sie eine Schleife haben, die inkrementell auf einen String-Wert addiert, da die Performance-Implikationen der Verkettung für lange Strings sehr groß sein können Negativ.
+0

stimmten zu, dass es eine bessere Methode ist, StringBuilder für solche Dinge zu verwenden (aber in diesem Beispiel eine * sehr * kleine Leistungssteigerung), ich habe nur versucht, das Beispiel einfacher zu halten. Wenn jemand meine Lösung an SB anpassen möchte, lass es mich wissen; es wäre nur ein paar Zeilen Unterschied. – iliketocode

+0

Hallo Peter! Zuerst wollte ich Regex verwenden, aber später gab ich nach dem Überprüfen des Beispielcodes mit Japanisch auf. Am Ende ist es nicht so kompliziert und ich mag das Konzept der Verwendung von '<>', um jeden Teil des Regex-Ausdrucks zu bezeichnen (was ist der Name dieses Attributs?). Es ist eine sehr interessante Herangehensweise, werde es heute mehr überprüfen und vielleicht mit ein paar Fragen zurückkommen, wenn es Ihnen nichts ausmacht! – Coloris

+0

Ich habe überhaupt keine Fragen. Es ist jedoch besser, Fragen in Kommentaren auf Dinge zu beschränken, die Sie stellen müssen, um eine Antwort besser zu verstehen (vor allem, wenn diese Frage Mängel in der Antwort hervorhebt, damit ich die Antwort bearbeiten und verbessern kann). Umfassendere Fragen, die vom aktuellen Thema abweichen, werden am besten in einer neuen Stack Overflow-Frage behandelt. :) Was den "Namen dieses Attributs" angeht, weiß ich nicht, ob es einen technischen Begriff gibt. Es ist nur der Name der Erfassungsgruppe. Weitere Informationen finden Sie unter https://msdn.microsoft.com/en-us/library/az24scfc(v=vs.110).aspx#grouping_constructs. –

1

Dies sollte es tun (und sogar reichten Indizes behandeln), bezogen auf die Formatierung der Eingabezeichenfolge Sie

using System; 
using System.Collections.Generic; 

public class stringParser 
{ 
    private struct IndexElements 
    { 
     public int start; 
     public int end; 
     public string value; 
    } 

    public static void Main() 
    { 
     //input string 
     string myString = "子で子にならぬ時鳥,0:こ;2:こ;7-8:ほととぎす"; 
     int wordIndexSplit = myString.IndexOf(','); 
     string word = myString.Substring(0,wordIndexSplit); 
     string indices = myString.Substring(wordIndexSplit + 1); 

     string[] eachIndex = indices.Split(';'); 
     Dictionary<int,IndexElements> index = new Dictionary<int,IndexElements>(); 
     string[] elements; 
     IndexElements e; 
     int dash; 
     int n = 0; 
     int last = -1; 
     string results = ""; 

     foreach (string s in eachIndex) 
     { 
      e = new IndexElements(); 
      elements = s.Split(':'); 
      if (elements[0].Contains("-")) 
      { 
       dash = elements[0].IndexOf('-'); 
       e.start = int.Parse(elements[0].Substring(0,dash)); 
       e.end = int.Parse(elements[0].Substring(dash + 1)); 
      } 
      else 
      { 
       e.start = int.Parse(elements[0]); 
       e.end = e.start; 
      } 
      e.value = elements[1]; 

      index.Add(n,e); 
      n++; 
     } 

     //this is the part that takes the "setup" from the parts above and forms the result string 
     //loop through each of the "indices" parsed above 
     for (int i = 0; i < index.Count; i++) 
     { 
      //if this is the first iteration through the loop, and the first "index" does not start 
      //at position 0, add the beginning characters before its start 
      if (last == -1 && index[i].start > 0) 
      { 
       results += word.Substring(0,index[i].start); 
      } 
      //if this is not the first iteration through the loop, and the previous iteration did 
      //not stop at the position directly before the start of the current iteration, add 
      //the intermediary chracters 
      else if (last != -1 && last + 1 != index[i].start) 
      { 
       results += word.Substring(last + 1,index[i].start - (last + 1)); 
      } 

      //add the space before the "index" match, the actual match, and then the formatted "index" 
      results += " " + word.Substring(index[i].start,(index[i].end - index[i].start) + 1) 
       + "[" + index[i].value + "]"; 
      //remember the position of the ending for the next iteration 
      last = index[i].end; 
     } 

     //if the last "index" did not stop at the end of the input string, add the remaining characters 
     if (index[index.Keys.Count - 1].end + 1 < word.Length) 
     { 
      results += word.Substring(index[index.Keys.Count-1].end + 1); 
     } 
     //trimming spaces that may be left behind 
     results = results.Trim(); 

     Console.WriteLine("INPUT - " + myString); 
     Console.WriteLine("OUTPUT - " + results); 

     Console.Read(); 
    } 
} 

input - 子で子にならぬ時鳥,0:こ;2:こ;7-8:ほととぎす

output - 子[こ]で 子[こ]にならぬ 時鳥[ほととぎす]

Hinweis haben-, dass dies auch funktionieren sollte mit Zeichen das englische Alphabet, wenn Sie stattdessen Englisch verwenden wollten

input - iliketocodeverymuch,2:A;4-6:B;9-12:CDEFG

output - il i[A]k eto[B]co deve[CDEFG]rymuch

+0

Hallo iliketocode! Ich verstehe den größten Teil des Codes, nur der "for" -Teil ist für mich etwas kryptisch. Würde es Ihnen etwas ausmachen, mehr Details auszuarbeiten, was es macht? Ich versuche, es durch den Debugger herauszufinden, aber würde einige Hinweise schätzen! – Coloris

+0

@Coloris Ich habe gerade einige Kommentare in diesen Teilen des Codes hinzugefügt. Lass es mich wissen, wenn du noch irgendwelche Fragen hast. Ich bin nicht sicher, wie Sie diesen Code verwenden, aber wenn es eine Chance gibt, dass die Eingabezeichenfolgen eine falsche Formatierung haben, möchten Sie zunächst eine Fehlerüberprüfung durchführen, um sicherzustellen, dass die Formatierung korrekt ist. Dann könnten Sie die korrekt formatierten Strings in den Mechanismus stecken, den ich geschrieben habe, um die endgültigen Ergebnisse zu erhalten. – iliketocode