2017-10-23 8 views
-3

Ich versuche, ein Programm in C++ zu schreiben, um eine Zeichenfolge zu normalisieren, indem ich jeden Großbuchstaben in Kleinbuchstaben umwandelt.String.length() gibt ein falsches Ergebnis zurück

Auch ich habe es mit einigen Sonderzeichen zu tun, da meine Muttersprache Spanisch ist, und es soll auch mit spanischen Wörtern funktionieren. Aus irgendeinem Grund gab ich eine Zeichenfolge von meinem normalize() zurück, konnte aber nicht cout es.

Also, damit es funktioniert, musste ich es ausdrucken, als ob es ein Array wäre, und es funktionierte für die meisten Fälle, weil ich word.length() benutzte. Als ich jedoch zu result.length() wechselte, gab es mir immer eine gerade 0. Ich kann nicht herausfinden, was das Problem ist, vielleicht muss ich einen Nullabschluss hinzufügen, um zu length() so zu arbeiten, kann seine Arbeit tun?

#include <iostream> 
#include <string> 

using namespace std; 

string normalize(string word) 
{ 
    string result; 
    int j = 0; 
    for (int i = 0; i < word.length(); i++) 
    { 
     if (word[i] >= 'A' && word[i] <= 'Z') 
     { 
      result[j] = tolower(word[i]); 
     } 
     else 
     { 
      if (word[i] == char(0xC3)) 
      { 
       switch (word[i + 1]) 
       { 
        case char(0xA1): 
         word[j] = 'a'; 
         break; 
        case char(0xA9): 
         word[j] = 'e'; 
         break; 
        case char(0xAD): 
         word[j] = 'i'; 
         break; 
        case char(0xB3): 
         word[j] = 'o'; 
         break; 
        case char(0xBA): 
         word[j] = 'u'; 
         break; 
        case char(0xBC): 
         word[j] = 'u'; 
         break; 
        case char(0x81): 
         word[j] = 'a'; 
         break; 
        case char(0x89): 
         word[j] = 'e'; 
         break; 
        case char(0x8D): 
         word[j] = 'i'; 
         break; 
        case char(0x93): 
         word[j] = 'o'; 
         break; 
        case char(0x9A): 
         word[j] = 'u'; 
         break; 
        case char(0x9C): 
         word[j] = 'u'; 
         break; 
       } 
       i++; 
      } 
      else 
       result[j] = result[i]; 
     } 
     j++; 
    } 
    return result; 
} 

int main() 
{ 
    int counter = 0; 
    string word; 

    while (cin >> word) 
    { 
     counter++; 
     string result = normalize(word); 
     cout << counter << ". "; 
     for (int i = 0; i < result.length(); i++) 
     { 
      cout << result[i]; 
     } 
     cout << endl; 
    } 
    return 0; 
} 
+0

Bitte Fügen Sie den Quellcode Ihrer 'normalize'-Funktion hinzu –

+0

Da Sie den Code, der wahrscheinlich das Problem hat, entfernen, werden wir Schwierigkeiten haben, Ihnen zu helfen. Auch ist off Thema wegen: _ "Fragen, die Debugging-Hilfe suchen (" warum funktioniert dieser Code nicht? ") Müssen das gewünschte Verhalten, ein spezifisches Problem oder einen Fehler und den kürzesten Code enthalten, der notwendig ist, um es in der Frage selbst zu reproduzieren." _ –

+0

Wenn 'cout << result' nicht funktioniert, dann sollten Sie arbeiten, um herauszufinden, warum (und es ist wahrscheinlich in dem Code, den Sie uns nicht zeigen). – crashmstr

Antwort

1

normalize() erwartet einen UTF-8-String als Eingabe. Wenn Sie die "speziellen" Zeichen behandeln, schreiben Sie keine Zeichen an result überhaupt, Sie schreiben sie stattdessen zurück zu word. Selbst wenn Sie sie unter result schreiben, schreiben Sie sie nicht richtig, da Sie vor dem Auffüllen keinen Speicher für result zugewiesen haben. Sie sollten operator+= anstelle von operator[] verwenden oder mindestens result.resize(word.length()) aufrufen, bevor Sie die Schleife aufrufen, und dann result.resize(j) aufrufen, nachdem Sie die Schleife verlassen haben.

etwas ähnlich stattdessen versuchen:

string normalize(const string &word) 
{ 
    string result; 
    result.reserve(word.length()); 

    int i = 0; 
    while (i < word.length()) 
    { 
     char ch = word[i++]; 
     if (ch <= 0x7F) 
     { 
      result += (char) tolower(ch); 
     } 
     else if ((ch == 0xC3) && (i < word.length())) 
     { 
      ch = word[i++]; 
      switch (ch) 
      { 
       case 0x81: 
       case 0xA1: 
        result += 'a'; 
        break; 
       case 0x89: 
       case 0xA9: 
        result += 'e'; 
        break; 
       case 0x8D: 
       case 0xAD: 
        result += 'i'; 
        break; 
       case 0x93: 
       case 0xB3: 
        result += 'o'; 
        break; 
       case 0x9A: 
       case 0x9C: 
       case 0xBA: 
       case 0xBC: 
        result += 'u'; 
        break; 
       default: 
        result += '?'; 
        break; 
      } 
     } 
     else 
      result += '?'; 
    } 
    return result; 
} 

jedoch, dass gesagt wird, was normalize() tun wird, ist nicht der richtige Weg, UTF-8 im Allgemeinen zu behandeln. Was Sie suchen, heißt "Transliteration", was viel mehr bedeutet als Ihre einfache Implementierung. Sie sollten stattdessen eine dedizierte Unicode-Bibliothek wie ICONV oder ICU verwenden. Aber wenn Sie gehen, um es manuell zu tun, zumindest dekodieren und verarbeiten die UTF-8 richtig, zum Beispiel:

string normalize(const string &word) 
{ 
    // TODO: normalize word using Unicode Normalization Form NFC first... 

    string result; 
    result.reserve(word.length()); 

    int i = 0; 
    while (i < word.length()) 
    { 
     uint8_t ch = (uint8_t) word[i++]; 
     int32_t cp; 
     int count; 

     if ((ch & 0x80) == 0x00) 
     { 
      cp = (ch & 0x7F); 
      count = 0; 
     } 
     else if ((ch & 0xE0) == 0xC0) 
     { 
      cp = ch & 0x1F; 
      count = 1; 
     } 
     else if ((ch & 0xF0) == 0xE0) 
     { 
      cp = ch & 0x0F; 
      count = 2; 
     } 
     else if ((ch & 0xF8) == 0xF0) 
     { 
      cp = ch & 0x07; 
      count = 3; 
     } 
     else 
     { 
      result += '?'; 
      continue; 
     } 

     bool ok = ((i+count) <= word.length()); 

     for (int j = 0; (ok) && (j < count); ++j) 
     { 
      ch = (uint8_t) word[i++]; 
      if ((ch & 0xC0) != 0x80) 
      { 
       ok = false; 
       break; 
      } 
      cp <<= 6; 
      cp |= (ch & 0x3F); 
     } 

     if (!ok) 
     { 
      result += '?'; 
     } 
     else 
     { 
      switch (cp) 
      { 
       case 0x00C1: 
       case 0x00E1: 
        result += 'a'; 
        break; 
       case 0x00C9: 
       case 0x00E9: 
        result += 'e'; 
        break; 
       case 0x00CD: 
       case 0x00ED: 
        result += 'i'; 
        break; 
       case 0x00D3: 
       case 0x00F3: 
        result += 'o'; 
        break; 
       case 0x00DA: 
       case 0x00DC: 
       case 0x00FA: 
       case 0x00FC: 
        result += 'u'; 
        break; 
       default: 
        if (cp <= 0x007F) 
         result += (char) tolower(cp); 
        else 
         result += '?'; 
        break; 
      } 
     } 
    } 
    return result; 
} 

Alternativ, wenn Sie mit C++ 11 oder höher:

string normalize(const string &word) 
{ 
    u32string u32 = codecvt_utf8<char32_t>{}.from_bytes(word); 

    // TODO: normalize u32 using Unicode Normalization Form NFC first... 

    string result; 
    result.reserve(u32.length()); 

    for (char32_t cp : u32) 
    { 
     switch (cp) 
     { 
      case 0x00C1: 
      case 0x00E1: 
       result += 'a'; 
       break; 
      case 0x00C9: 
      case 0x00E9: 
       result += 'e'; 
       break; 
      case 0x00CD: 
      case 0x00ED: 
       result += 'i'; 
       break; 
      case 0x00D3: 
      case 0x00F3: 
       result += 'o'; 
       break; 
      case 0x00DA: 
      case 0x00DC: 
      case 0x00FA: 
      case 0x00FC: 
       result += 'u'; 
       break; 
      default: 
       if (cp <= 0x007F) 
        result += (char) tolower(cp); 
       else 
        result += '?'; 
       break; 
     } 
    } 
    return result; 
} 
Verwandte Themen