Präprozessor(?): Zeichen in Zeichenkette ersetzen

Gast #4394549
Ich habe ein Display mit einem "komischen" Zeichensatz. Alphanumerische 
Zeichen (0..9, a..Z) sind ok, aber bei öäü gibt es Vertauschungen mit 
anderen Sonderzeichen.

Ich habe bei den Zeichenketten, die ich ins Flash lege, bisher immer 
statt z.B.

const __flash char TEST = "Töfftöff";

sowas geschrieben:

const __flash char TEST = "T%fft%ff";

So funktioniert das natürlich, ist aber eher unschön. Ich suche nach 
einer automatischen Lösung.
Eine Alternative ist natürlich, die Zeichen zur Laufzeit in der 
Displayroutine einzeln ersetzen zu lassen, was aber unnötig Rechenzeit 
und Flash kostet. Sowas müsste doch eigentlich auch zur Compilezeit bzw. 
im Präprozessor gehen? Hat jemand Tipps?
Gast
Ich möchte die Texte einfach auf natürliche Art und Weise schreiben. 
Ohne Sonderzeichen dazwischen, ohne \x-Verrenkungen. Wenn ich "Sülze" 
ausgeben will, möchte ich "Sülze" schreiben.
Gast
..besser wartbar wirds mit ein paar lesbaren Defines, z.B. sowas in der 
Art:
1
#define sAUML  "\x84"
2
#define sOUML  "\x94"
3

4
const char* const pLeberkaes = "Leberk" sAUML "se";
5
const char* const pKnoedel   = "Kn" sOUML "del";

> Wenn ich "Sülze" ausgeben will, möchte ich "Sülze" schreiben.

Textersetzung pre-compile-Event oder zur Laufzeit machen. Hat aber alles 
Vor- und Nachteile, such Dir aus, welche Du haben willst.
Otto Normalverbraucher schrieb:
> Ohne Sonderzeichen dazwischen, ohne \x-Verrenkungen. Wenn ich "Sülze"
> ausgeben will, möchte ich "Sülze" schreiben.

Ich möcht' auch viel. Manchmal muß man halt mit dem zufrieden sein, was 
man kriegt ;).

Du kannst natürlich auch dein komisches Display wegschmeissen und dir 
eins kaufen, das mit Sonderzeichen besser umgehen kann.

Wenn's dir das wert ist.
Gast
Otto Normalverbraucher schrieb:
> as aber unnötig Rechenzeit
> und Flash kostet.

Ist der Display-Code so laufzeitrelevant, dass das so schlimm wäre? Ich 
kenne deine Anwendung nicht, aber für ein paar Statusmeldungen auf einem 
Display kann man sich für jedes Zeichen durchaus ein switch-case mit
8 Möglichkeiten (ÄÖÜäöüß, default) leisten. Das ist immer noch um einige 
Größenordnungen schneller, als man lesen kann.
Persönliche Seite
Und wie wär's mit Fallunterscheidungen in der Ausgaberoutine?
1
extern void real_write_c (char);
2

3
static char map_uml (char c)
4
{
5
    switch (c)
6
    {
7
        default: break;
8
        case 'ä': c = '\x12'; break;
9
        case 'ö': c = '\x8f'; break;
10
        ...
11
    }
12
    return c;
13
}
14

15
void write_c (char c)
16
{
17
    real_write_c (map_ump (c));
18
}
Gast
im Sourcecode-Text ganz normal schreiben damit man es
auch vernünftig lesen kann.
In der LcdWriteChar() die Umlaute, Sonderzeichen etc. bei
der Ausgabe durch die entsprechenden Werte des LCD-Zeichensatzes
ersetzen.
Persönliche Seite
In C++11 gehts auch ganz ohne Präprozessor:
1
#include <cstddef>
2
#include <array>
3
#include <cstdio>
4

5
template <typename T, T... I>
6
struct IntegerSequence {
7
  using value_type = T;
8
  static constexpr size_t size () { return sizeof... (I); }
9
};
10

11
namespace Helper {
12
  template <typename T, typename S1, typename S2>
13
  struct ConcatSequence;
14

15
  template <typename T, T... S1, T... S2>
16
  struct ConcatSequence<T, IntegerSequence<T, S1...>, IntegerSequence<T, S2...>> {
17
    using type = IntegerSequence<T, S1..., (sizeof...(S1) + S2)...>;
18
  };
19

20
  template <typename T, T N, bool isZero, bool isOne>
21
  struct GenSeqI;
22
}
23
template <typename T, T N>
24
using GenSeq = typename Helper::GenSeqI<T, N, N == 0, N == 1>::type;
25

26
namespace Helper {
27
  template <typename T, T N>
28
  struct GenSeqI<T, N, false, false> {
29
    using type = typename ConcatSequence<T, GenSeq<T, N/2>, GenSeq<T, N-N/2>>::type;
30
  };
31
  template <typename T, T N>
32
  struct GenSeqI<T, N, true, false> {
33
    using type = IntegerSequence<T>;
34
  };
35
  template <typename T, T N>
36
  struct GenSeqI<T, N, false, true> {
37
    using type = IntegerSequence<T, 0>;
38
  };
39
}
40

41
inline constexpr char replace (char value) {
42
  return
43
    value == 'ö' ? 'o' :
44
    value == 'ä' ? 'a' :
45
    value == 'ü' ? 'u' :
46
    value;
47
}
48

49
template <size_t N, size_t... I>
50
inline constexpr const std::array<char, N> replace (const char (&str) [N], IntegerSequence<size_t, I...>*) {
51
  return {{ replace (str [I])... }};
52
}
53

54
template <size_t N>
55
inline constexpr const std::array<char, N> replace (const char (&str) [N]) {
56
  return replace<N> (str, static_cast<GenSeq<size_t, N>*> (nullptr));
57
}
58

59
/// ----------
60

61
constexpr auto myString1 = replace ("Hällö Leüte");
62

63
int main () {
64
  puts (myString1.data ());
65
}

Hier werden testweise Umlaute durch die normalen Vokale ersetzt, das 
kannst du dann deinen Bedürfnissen anpassen. Die Ersetzung erfolgt zur 
Compile-Zeit und im Programm landet der fertig verarbeitete String. Zum 
Kompilieren sollte dieser Code als ISO-8859-15 gespeichert werden, denn 
bei UTF-8 nehmen Umlaute mehrere Bytes ein und 'ä' funktioniert nicht 
mehr.

Wichtig ist dass pro String-Literal eine globale/statische Variable 
(hier myString1) angelegt wird, auf der man dann später .data() aufrufen 
kann um den "const char*" zu erhalten.
Einfach nur replace ("...").data() funktioniert nicht.
Persönliche Seite
Johann L. schrieb:
> Boah, wer will solchen Monstercode lesen, pflegen oder verstehen?
Nicht so schlimm wenn man C++ kann.
> Und mit avr-gcc übersetzbar ist er auch nicht...
Stimmt, weil dem AVR-GCC ein paar C++ Header Files fehlen. Im Anhang 
eine Version die std::array nachbildet und auch mit dem AVR-GCC 
funktioniert, und für die Grundlagen die C-Header verwendet.

Habe außerdem noch ein Makro hinzugefügt das Lambdas missbraucht um die 
Verwendung zu vereinfachen (doch keine globale Variable nötig):
1
puts (LCD_REPLACE_STR("Hällö Leüte"));
Angehängte Dateien:
Gast
Ansonsten hätte ich einfach mal einen Perl-Script geschrieben, der die 
Zeichen ersetzt. Die Strings einfach in eine separate Header-Datei 
schreiben und mit dem Script die relevanten Zeichen ersetzen.

(sed, awk und Konsorten gingen natürlich auch).

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 10 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.