2009-09-02 13 views
16

Próbuję wyprowadzić ciąg Unicode w formacie RTF. (Przy użyciu C# WinForm)Jak wypisać ciąg Unicode do formatu RTF (przy użyciu C#)

From wikipedia:

Jeśli wymagane jest ucieczka UNICODE, to słowo kontrolne \ u jest używana, a następnie przez 16-bitową liczbę całkowitą dziesiętnych podając numer kodowy Unicode. Dla korzyści programów bez obsługi Unicode, musi następować najbliższa reprezentacja tego znaku na określonej stronie kodowej. Na przykład \ u1576? nadałby arabskiemu literowi beh, określając, że starsze programy, które nie mają obsługi Unicode, powinny renderować je jako znak zapytania.

Nie wiem, jak przekonwertować znak Unicode na kod kodowy Unicode ("\ u1576"). Konwersja do UTF 8, UTF 16 i podobnych jest prosta, ale nie wiem jak przekonwertować na codepoint.

scenariusz, w którym używam to:

  • czytam istniejący plik RTF do string (Czytam szablon)
  • string.replace # # Token z MyUnicodeString (szablon jest zapełnić danymi)
  • Napisz wynik do innego pliku RTF.

Problem pojawia się, gdy znaki Unicode przybył

Odpowiedz

25

Pod warunkiem, że wszystkie znaki, że jesteś wyżywienie dla istnieć w Basic Multilingual Plane (jest to mało prawdopodobne, że potrzebujesz czegoś więcej), wystarczy proste kodowanie UTF-16.

Wikipedia:

wszystkie możliwe punkty kodowe z U + 0000 przez U + 10FFFF, z wyjątkiem zastępczych punktów kodowych U + D800-U + DFFF (które nie są znaki), są jednoznacznie odwzorowane przez UTF-16 niezależnie od aktualnego lub przyszłego przydziału lub użycia znaku w punkcie kodowym w postaci .

Poniższy przykładowy program ilustruje robi coś na wzór tego, co chcesz:

static void Main(string[] args) 
{ 
    // ë 
    char[] ca = Encoding.Unicode.GetChars(new byte[] { 0xeb, 0x00 }); 
    var sw = new StreamWriter(@"c:/helloworld.rtf"); 
    sw.WriteLine(@"{\rtf 
{\fonttbl {\f0 Times New Roman;}} 
\f0\fs60 H" + GetRtfUnicodeEscapedString(new String(ca)) + @"llo, World! 
}"); 
    sw.Close(); 
} 

static string GetRtfUnicodeEscapedString(string s) 
{ 
    var sb = new StringBuilder(); 
    foreach (var c in s) 
    { 
     if (c <= 0x7f) 
      sb.Append(c); 
     else 
      sb.Append("\\u" + Convert.ToUInt32(c) + "?"); 
    } 
    return sb.ToString(); 
} 

Ważną informacją jest Convert.ToUInt32(c) które zasadniczo zwraca wartość punktową kodu dla znaku w pytaniu.Wyjście RTF dla unicodu wymaga dziesiętnej wartości Unicode. Kodowanie System.Text.Encoding.Unicode odpowiada UTF-16 zgodnie z dokumentacją MSDN.

+0

hmmmm, bardzo interesujący punkt.Jeśli to prawda, to prawdopodobnie gdzieś w mojej logice jest błąd ... odpowiedź Iana Kempa ma o wiele więcej sensu ... będę googlować – Emir

+0

Dziękuję, na przykład, działa! – Emir

1

Trzeba będzie przekonwertować ciąg do byte[] tablicy (przy Encoding.Unicode.GetBytes(string)), następnie pętli tej tablicy i poprzedzić znak \ i u do wszystkich znaków Unicode ty odnaleźć. Kiedy następnie przekształcisz tablicę z powrotem w ciąg znaków, będziesz musiał zostawić znaki Unicode jako liczby.

Na przykład, jeśli tablica wygląda następująco:

byte[] unicodeData = new byte[] { 0x15, 0x76 }; 

byłoby stać:

// 5c = \, 75 = u 
byte[] unicodeData = new byte[] { 0x5c, 0x75, 0x15, 0x76 }; 
+0

Witam, dziękuję za odpowiedź, Próbowałem zaimplementować twoje rozwiązanie, niestety to nie działa. Myślę, że to dlatego, że istnieje różnica między kodowaniem Codepoint i UTF16 (Encoding.Nicode). Sugerujesz, żebym wyprowadził bajty z kodowania UTF16, gdzie Codepoint jest wyłączony. (A to działa dla wielu postaci, ale nie dla wszystkich). – Emir

+0

Ta odpowiedź również zadziała, Prawdopodobnie miałem błąd w moim kodzie podczas testowania go. Dziękuję za odpowiedź i za poświęcony czas. – Emir

+0

Jedyny problem polega na tym, że po przekonwertowaniu na tablicę bajtową utracisz kodowanie. Najlepiej zostawić go jako UTF-16 i przepuścić przez niego. – Brain2000

18

Poprawiono kod z przyjętą odpowiedzi - dodał szczególny charakter ucieczki, jak opisano w tym link

static string GetRtfUnicodeEscapedString(string s) 
{ 
    var sb = new StringBuilder(); 
    foreach (var c in s) 
    { 
     if(c == '\\' || c == '{' || c == '}') 
      sb.Append(@"\" + c); 
     else if (c <= 0x7f) 
      sb.Append(c); 
     else 
      sb.Append("\\u" + Convert.ToUInt32(c) + "?"); 
    } 
    return sb.ToString(); 
} 
0

oparty na specyfikacji, oto niektóre kod w Javie, który został przetestowany i działa:

public static String escape(String s){ 
     if (s == null) return s; 

     int len = s.length(); 
     StringBuilder sb = new StringBuilder(len); 
     for (int i = 0; i < len; i++){ 
      char c = s.charAt(i); 
      if (c >= 0x20 && c < 0x80){ 
       if (c == '\\' || c == '{' || c == '}'){ 
        sb.append('\\'); 
       } 
       sb.append(c); 
      } 
      else if (c < 0x20 || (c >= 0x80 && c <= 0xFF)){ 
       sb.append("\'"); 
       sb.append(Integer.toHexString(c)); 
      }else{ 
       sb.append("\\u"); 
       sb.append((short)c); 
       sb.append("??");//two bytes ignored 
      } 
     } 
     return sb.toString(); 
} 

Ważne jest to, że musisz dodać 2 znaki (blisko znaku Unicode lub po prostu użyć? Zamiast) po kodowanym Esode. ponieważ kod Unicode zajmuje 2 bajty.

Również specyfikacja mówi, że powinieneś użyć wartości ujemnej, jeśli kod jest większy niż 32767, ale w moim teście jest to w porządku, jeśli nie używasz wartości ujemnej.

Oto specyfikacja:

\ un Ten parametr reprezentuje pojedynczy znak Unicode, który nie ma odpowiednika reprezentacji ANSI na podstawie bieżącej strony kodowej ANSI. N oznacza wartość znaku Unicode wyrażoną jako liczba dziesiętna. Po tym słowie kluczowym następuje odpowiednik znaku (ów) w reprezentacji ANSI. W ten sposób stare czytniki zignorują słowo kluczowe \ uN i prawidłowo podniosą reprezentację ANSI. Po napotkaniu tego słowa kluczowego czytelnik powinien zignorować następne N znaków, gdzie N odpowiada ostatniej napotkanej wartości \ ucN.

Podobnie jak w przypadku wszystkich słów kluczowych w formacie RTF, może istnieć przestrzeń kończąca słowa kluczowego (przed znakami ANSI), która nie jest wliczana w znaki do pominięcia. Chociaż nie jest to prawdopodobne (lub zalecane), słowo kluczowe \ bin, jego argument i następujące dane binarne są uważane za jeden znak dla celów pomijania. Jeśli napotkany zostanie znacznik ogranicznika zakresu RTF (to jest nawias otwierający lub zamykający) podczas skanowania możliwych do pominięcia danych, dane możliwe do pominięcia są uważane za zakończone przed ogranicznikiem. Dzięki temu czytelnik może wykonać podstawowe odzyskiwanie po błędzie. Aby dołączyć ogranicznik RTF do danych możliwych do pominięcia, musi on być reprezentowany przy użyciu odpowiedniego symbolu kontrolnego (to jest, z odwróconym ukośnikiem odwrotnym), jak w postaci zwykłego tekstu. Każde słowo lub symbol kontrolny RTF jest traktowany jako pojedynczy znak do celów liczenia możliwych do pominięcia znaków.

Pisarz RTF, napotykając znak Unicode bez odpowiadającego mu znaku ANSI, powinien wypisać \ uN, a następnie najlepszą reprezentację ANSI, którą może zarządzać. Ponadto, jeśli znak Unicode tłumaczy się na strumień znaków ANSI z liczbą bajtów różniącą się od bieżącej liczby bajtów znaków Unicode, powinien wyemitować słowo kluczowe \ uCN przed słowem kluczowym \ uN, aby powiadomić czytelnika o zmianie.

Słowa sterujące RTF ogólnie akceptują podpisane 16-bitowe liczby jako argumenty. Z tego powodu wartości Unicode większe niż 32767 muszą być wyrażone jako liczba ujemna

Powiązane problemy