Forum: Compiler & IDEs Präprozessor(?): Zeichen in Zeichenkette ersetzen


von Otto Normalverbraucher (Gast)


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?

von Otto Normalverbraucher (Gast)


Lesenswert?

Achso, avr-gcc.

von Rolf M. (rmagnus)


Lesenswert?

Ist es denn irgendein Standard-Zeichensatz? Dann könntest du den im gcc 
als execution character set einstellen.

von Otto Normalverbraucher (Gast)


Lesenswert?

Standard ist da leider gar nichts. Da liegen u.a. auch japanische 
Zeichen zwischen den Umlauten usw.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Otto Normalverbraucher schrieb:

Und sowas?

>#define oe "\x8a"
> const __flash char Toeff_Toeff[] = "T"oe"fft"oe"ff";

von Markus F. (mfro)


Lesenswert?

Wenn Du weißt, welchen Zeichencode Du ausgeben willst, wieso schreibst 
Du ihn nicht einfach hin?
1
const char *leberkaes = "Leberk\x84s";
2
const char *knoedel = "Kn\x94del";

von Otto Normalverbraucher (Gast)


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.

von g457 (Gast)


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.

von Markus F. (mfro)


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.

von Tom (Gast)


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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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
}

von MitLeser (Gast)


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.

von MitLeser (Gast)


Lesenswert?

schade war zu spät :-)
Johann L. hat es auf den Punkt gebracht.

von Niklas G. (erlkoenig) Benutzerseite


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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Niklas G. schrieb:
> In C++11 gehts auch ganz ohne Präprozessor:

Boah, wer will solchen Monstercode lesen, pflegen oder verstehen?

Und mit avr-gcc übersetzbar ist er auch nicht...

von Klaus (Gast)


Lesenswert?

Vielleicht fällt ja noch jemandem was ein, wenn der TO mal die 
Bezeichnung des Dipslays postet - oder sogar so nett ist und das 
Datenblatt verlinkt.

von Niklas G. (erlkoenig) Benutzerseite


Angehängte Dateien:

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"));

von Klaus (Gast)


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).

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.