Präprozessor(?): Zeichen in Zeichenkette ersetzen

Gast #4394549
Lesenswert?

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 #4395027
Lesenswert?

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 #4395034
Lesenswert?

..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.
#4395042
Lesenswert?

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 #4395052
Lesenswert?

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.
Gast #4395075
Lesenswert?

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 #4395133
Lesenswert?

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 #4395267
Lesenswert?

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 #4395278
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren