String ohne New Line

Kann man bei einem empfangenen String die new lines '\n' rauslöschen und als string speichern?
Ich habe z.B. so etwas was mir am seriellen Monitor ausgegeben wird:

hallogustavwi
egehtesdir

Jetzt möchte ich dies als String ohne die new line haben, also alles am Stück ohne neue Zeile. Mit dem Befehl trim() kann man ja nur die Enden löschen, oder? Hat da jemand ein Beispiel wie man das macht?

Nein. Doku durchlesen:

https://www.arduino.cc/reference/de/language/variables/data-types/string/functions/trim/

Wobei die wörtliche Übersetzung von "whitespace" mit "Leerzeichen" nicht richtig ist.

Man kann Zeichenketten auch sehr einfach per Hand einlesen. Dann hat man totale Kontrolle und die Steuerzeichen werden erst gar nicht abgespeichert:

Die Doku von C++ hält noch weitere Möglichkeiten bereit:

void setup() {
  Serial.begin(9600);
  Serial.println("\nStart");
  char e[] = {"hallogustavwi\negehtesdir"};
  Serial.println(e);
  Serial.println();
  char buf1[80];
  char buf2[80];
  sscanf (e, "%s %s", buf1, buf2);
  Serial.println(buf1);
  Serial.println(buf2);
  Serial.println();
  strncat (buf1, buf2, 79);
  Serial.println(buf1);
  Serial.println();

  char PufferChar[] = {"hallogustavwi\negehtesdir"};
  byte j = 0;
  for ( byte i = 0; PufferChar[i] != 0; i++ ) {
    if (PufferChar[i] == '\n') {
      j++;
    }
    PufferChar[i] = PufferChar[j];
    j++;
  }
  Serial.println(PufferChar);
}

void loop() {}

ich würde sagen hängt davon ab wie du die Daten empfängst. Ein Mustersketch der zeigt wie du die Daten empfängst würde helfen dir eine passende Antwort geben zu können.

Ich glaube ja Du meinst nicht String, sondern Zeichenkette.

DreiZeiler.

Wenn Du die ganzen Seriellen Ausgaben rauslöscht.

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
}

void loop()
{
  readLineSerialInCharArray();
}

void readLineSerialInCharArray()
{
  char meinString[32] = {0};
  unsigned int meinePosition = 0;
  char readChar;
  while (Serial.available() > 0)
  {
    readChar = Serial.read();
    if (!isControl(readChar))
    {
      meinString[meinePosition] = readChar;
      meinePosition++;
    }
    else if (readChar == '\n')
    {
      Serial.print(F("Mein String hat jetzt folgenden Inhalt: "));
      Serial.print(meinString);
      Serial.print(F(" mit Länge: "));
      Serial.println(meinePosition);
      Serial.println();
    }
  }
}

Das geht schief, wenn die komplette Zeichenkette nicht im Aufruf da ist, was bei Serial durchaus möglich ist. Diese Routine umgeht das Problem:

// Länge Nutzdaten + 1
const uint8_t BUFLEN = 11;
char puffer[BUFLEN];

// liest bis zum Zeilenende oder bis der Puffer voll ist und gibt dann true zurück
boolean readSerialNL() {
static uint8_t idx = 0;
static boolean fertig = false;
char c;
  // Neubeginn initialisieren
  if (fertig && idx > 0) {
    idx = 0;
    fertig = false;
  }
  if (Serial.available()) {  // hier könnte man evtl. auch while nehmen
    c = Serial.read();
    if (c == '\n' || idx == BUFLEN -1) { // Zeilenvorschub oder voll
      puffer[idx] = '\0';
      fertig = true;
    }
    else if (c >= 0x20 && idx < BUFLEN -1) { // keine Steuerzeichen
      puffer[idx++] = c;
    }
  }
  return fertig;
}

void setup() {
  Serial.begin(115200);
  Serial.println("Start");
}

void loop() {
  // solange lesen lassen, bis Zeilenende erkannt wurde
  boolean anzeigen = readSerialNL();
  if (anzeigen) Serial.println(puffer);
}

Gruß Tommy

Das ist richtig - macht es aber bei allen anderen auch :wink:
Da hilft genau das static für zwei Vars und ein memset.

Hier vervollständigt:

void readLineSerialInCharArray()
{
  static char meinString[32] = {0};
  static unsigned int meinePosition = 0;
  char readChar;
  while (Serial.available() > 0)
  {
    readChar = Serial.read();
    if (!isControl(readChar))
    {
      meinString[meinePosition] = readChar;
      meinePosition++;
    }
    else if (readChar == '\n')
    {
      Serial.print(F("Mein String hat jetzt folgenden Inhalt: "));
      Serial.print(meinString);
      Serial.print(F(" mit Länge: "));
      Serial.println(meinePosition);
      Serial.println();
      memset(meinString, 0, sizeof(meinString));
    }
  }
}

Den gibt es dann auch noch erweitert, wenn "meinePosition" über die Puffergröße hinausläuft, weil gar kein Newline kommt.

Nö, meiner hat damit kein Problem, Dein zweiter ist auch nicht besser.

Gruß Tommy

Stimmt, da ist beim reinschreiben die Zeile

      meinePosition=0;

nicht eingefügt.

Das es den auch vollständig gibt, wenn kein newLine bis zum Ende des Puffers kommt, hatte ich geschrieben.
Da aber die Vorgabe den Puffer nicht überläuft, war das nicht nötig.

Das Wichtigste ist, dass egal wie langsam die Zeichen kommen, erst beim '\n' erkannt wird, dass die Eingabe fertig ist und das kann Deine Variante mit alles in einem while nicht erfüllen, egal was Du da weiterhin behauptest. (Jeder blamiert sich so gut er kann). Sieh einfach ein, das Deine Version dafür falsch ist und blamiere Dich nicht noch mehr.
Du hast doch sonst ganz gute Codes, warum jetzt dieser unnötige Spagat? Nur um auf Biegen und Brechen Recht behalten zu wollen?

Gruß Tommy

Die new line Character sind nicht am Ende bei meinen gesendeten Daten, sondern immer nach 19 oder 20 Zeichen. Das 20. Zeichen sollte der \n sein. Kann ich dann nicht auch mit readStringUntil('\n') die einzelnen Zeichen "addieren"?

Was soll der Sinn von '\n' sein, wenn es nicht am Ende einer definierten Datenmenge kommt?

Gruß Tommy

Die Daten werden von einem BLE Bluetooth Modul gesendet. Dieses macht immer 20byte grosse Packete und sendet diese. Wenn ich also einen Text sende, der heisst:

Hallo Gustav Wie geht es dir?

Dann erhalte ich ihn am seriellen Monitor so angezeigt:

HalloGustav Wie geh
t es dir?

Das 20. Zeichen ist das new line wie es scheint.
Um den String aber wieder normal zusammen zu haben müsste ich das new line löschen und zusammenfügen.

Genau das tut sie.
Sonst wäre ich aus der Rennbahn vor mehr als 100 Posts schon längst rausgeflogen.

Ich habe doch gleich am Anfang schon Code gepostet. Halt als Link. Das hat doch gereicht. :confused:

Ein Newline ist dazu da um eine Zeile abzuschließen. Das hört sich eher danach an als ob du zwei Zeilen hast und diese Zusammenfügen willst. Das kann man mit Strings doch einfach machen. Einlesen kann man sie aber trotzdem getrennt.

Vielleicht solltest du auch mal genauer erklären was das für Daten sind und wo die her kommen.

Lösungen dafür stehen in #2 und #3!

Ja.
Genau das ist das, was ich auch gepostet habe.
Baue Deinen Puffer

  static char meinString[32] = {0};

so gross, das alles reinpasst.
Also wäre Dein Puffer z.B. 40bytes gross.
So und nu kommt das wichtige ABER, was hier bisher nicht zur Sprache kam und was ich schon auf dem Plan hatte:

WANN ist Dein gesendeter String tatsächlich zu Ende?

Wenn Du eine Zeichenkette zerlegst, dann muss Du einen Anfang und ein Ende setzen. Wie willst Du sonst am Empfänger erkennen, ob es sich bei den empfangenen Daten um
-> den ersten
-> den zweiten
-> den dritten
-> den xten

Teil des Gesamtpaketes handelt?

Bei Post #3, sehe ich das richtig, dass das zwei Möglichleiten sind die da im Sketch stehen?

Wie der untere Teil, sowas hatte ich versucht, aber ich habe das Array anders eingelesen und nicht den ganzen String erhalten. Das sieht gut aus, das schau ich mir näher an!

Kannst Du mir noch erklären, was genau hier passiert:

sscanf (e, "%s %s", buf1, buf2);

Was macht das %s %s?

Wie es scheint? oder weisst Du das?

Ungeachtet dessen möchte ich, das Du folgenden Code einmal laufen lässt.
Leider hast Du Dich bisher verweigert auch nur ansatzweise zu zeigen wie Du arbeitest.

Es fehlen gänzlich alle notwendigen Infos, wie Du wo was einliest.
Auch ist nicht bekannt, welchen Kenntnisstand Du hast, auf dem aufgebaut werden kann.

Von daher mach was draus...

Du darfst alles übertragen.
Satzende ist !?. - was (noch) nicht geht und nicht übertragen werden darf ist: ;:, - dafür gibts dann später ggfls. eine Lösung.

JEDE(!) Nachricht soll mit einem Satzzeichen enden.
Ein . ein ! ein ? ist schick.
UND: Die Zeichenkette darf aktuell nur 200 Zeichen lang sein.
Das geht auch besser, aber erstmal sehen, was überhaupt geht.

Wenn Du das hast, würde mich die Ausgabe auf dem SerMon interessieren.

void setup()
{
  Serial.begin(115200);
  Serial.println(F("Start..."));
}

void loop()
{
  readLineSerialInCharArray();
}

void readLineSerialInCharArray()
{
  static char meinString[200] = {0};
  static unsigned int meinePosition = 0;
  char readChar;
  while (Serial.available() > 0)
  {
    readChar = Serial.read();
    if (isPunct(readChar))
    {
      Serial.print(F("Satzzeichen erkannt: "));
      Serial.println(readChar);
      Serial.println();
      meinString[meinePosition] = readChar;
      Serial.print(F("Nach Satzzeichen erkannt: "));
      Serial.println(meinString);
      memset(meinString, 0, sizeof(meinString));
      meinePosition = 0;
    }
    else if (!isControl(readChar))
    {
      meinString[meinePosition] = readChar;
      meinePosition++;
    }
    else if (readChar == '\n')
    {
      Serial.print(F("NewLine erkannt! "));
      Serial.print(F("Mein String hat jetzt folgenden Inhalt: "));
      Serial.print(meinString);
      Serial.print(F(" mit Länge: "));
      Serial.println(meinePosition);
      Serial.println(F("Lese weiter ein..."));
      Serial.println();
    }
  }
}

%s nimmt eine Zeichenkette "stopping at the first whitespace character found." Also e wird bis zum whitespace character nach buf1 kopiert, der Rest nach buf2.