String/character array validation routine does not properly evaluate a condition statement

I have a string validation routine as shown below. The problem I’m having is that in the validateTGWC function, the following condition statement does not evaluate properly:

if(c_buf[1] != 'B' || c_buf[1] != 'D')

I also get some garbage data at the end when I print out c_buf in validateTGWC function.

What’s going on?

Output:

Iteration: 0
c_buf=M12345.123456▒▒▒ ; TGWC=M12345.123456
testStrings[0]=M12345.123456 matched successfully.
Iteration: 1
c_buf=M12345.123456▒▒▒ ; TGWC=m12345.123456
testStrings[1]=m12345.123456 matched successfully.
Iteration: 2
c_buf=MB2345.123456▒▒▒ ; TGWC=mb2345.123456
No digit at pos 1...
TGWC must start with M[0-9], MB, or MD. char at 1 is: B
Iteration: 3
c_buf=MD2345.123456▒▒▒ ; TGWC=md2345.123456
No digit at pos 1...
TGWC must start with M[0-9], MB, or MD. char at 1 is: D
Iteration: 4
c_buf=MB2345.123456▒▒▒ ; TGWC=mB2345.123456
No digit at pos 1...
TGWC must start with M[0-9], MB, or MD. char at 1 is: B
Iteration: 5
c_buf=MD2345.123456▒▒▒ ; TGWC=mD2345.123456
No digit at pos 1...
TGWC must start with M[0-9], MB, or MD. char at 1 is: D
Iteration: 6
LT: Length Received: 12. TGWC must be 13 characters long.
Iteration: 7
c_buf=X12345.123456▒▒▒ ; TGWC=X12345.123456
TGWC must start with M
Iteration: 8
c_buf=M12345,123456▒▒ ; TGWC=M12345,123456
TGWC must have a . according to M#####.######
Iteration: 9
c_buf=M1X345.123X56▒▒▒   ; TGWC=M1X345.123X56
TGWC does not have a digit in position

Code:

String testStrings [] = {"M12345.123456",
								   "m12345.123456",
								   "mb2345.123456", 
								   "md2345.123456", 
								   "mB2345.123456",
								   "mD2345.123456",						   
								   "12345.123456", 
								   "X12345.123456", 
								   "M12345,123456", 
								   "M1X345.123X56"};
		  
		  
for(int k = 0; k<sizeof(testStrings)/sizeof(testStrings[0]); k++){
	Serial.printlnf("Iteration: %d ",k);


	if(validateTGWC(testStrings[k].c_str()))
		Serial.printlnf("testStrings[%d]=%s matched successfully.",k,testStrings[k].c_str());
}

bool validateTGWC(const char* TGWC){
  
  char c_buf[13] = {0};
  
  // Validate TGWC length is 13
  
  if(strlen(TGWC) != 13){ 
    Serial.printlnf("Length Received: %d. TGWC must be 13 characters long.",strlen(TGWC));
    return false;
  }  
  
  // Convert to uppercase alpha characters
  
  for(int i=0; i<13; i++){

	  c_buf[i] = toupper(TGWC[i]);
    
  }
  
  Serial.printlnf("c_buf=%s ; TGWC=%s",c_buf,TGWC);
  
  // Validate 1st character is M
  
  if(c_buf[0] !='M'){
    Serial.println(F("TGWC must start with M")); 
    return false;
  }
  
  // Validate 2nd character is (B|D|[0-9])
  
  /*
  if((strncmp(c_buf,"MBXXXX.XXXXXX",2) != 0) || strncmp(c_buf,"MDXXXX.XXXXXX",2) != 0){
	  	  Serial.printlnf("TGWC must start with M[0-9], MB, or MD. char at 1 is: %c, stncmp:%d", c_buf[1], strncmp(c_buf,"MBXXXX.XXXXXX",2)); 
	  return false;	  
  }
  */
  if(!isdigit(c_buf[1])){
	  Serial.println("No digit at pos 1...");
	  
	if(c_buf[1] != 'B' || c_buf[1] != 'D'){
	  Serial.printlnf("TGWC must start with M[0-9], MB, or MD. char at 1 is: %c", c_buf[1]); 
	  return false;	  
	}
  }
  
  // Validate 7th character is a period (.)
  if(c_buf[6] != '.'){
    Serial.println(F("TGWC must be separated by a period at position 7.")); 
    return false;
  }
  
  // Validate remaining characters are digits
  
  for(int i=0; i<13; i++){
    
    if(i > 1 && i != 6 && !isDigit(c_buf[i])){
      Serial.printlnf("TGWC does not have a digit in position",i+1);
      return false;
    }
    }
  
    return true;
  
    }

One problem is that since your strings are 13 characters long, c_buf needs to be 14 long to make room for the terminating 0; that’s the reason you’re getting some garbage data.

the problem with this,

if(c_buf[1] != 'B' || c_buf[1] != 'D')

is a problem with the logic. With the “or” logic, if it is not a B or it is not a D, the condition is satisfied; since the character can’t be both a D and a B, that if statement will always be true. You need to change “||” to “&&”.

It can be confusing when using != in multi-part comparisons. Another way to write it that makes it more clear, imo, is like so:

if(!(c_buf[1] == 'B' || c_buf[1] == 'D'))
1 Like

Ah yes, you are right about the terminating 0; I forgot about that!

And you’re right, the logic in the condition statement was wrong.

Validation works with the following code sets just for reference:

Version 1:

  // Validate 2nd character is (B|D|[0-9])
  if(!isdigit(c_buf[1])){
	  if(c_buf[1] != 'B'){
		  if(c_buf[1] != 'D'){
			  Serial.printlnf("TGWC must start with M[0-9], MB, or MD. char at 1 is: %c, ", c_buf[1]); 
			  return false;	  
		 }
	  }
  }

Version 2:

  // Validate 2nd character is (B|D|[0-9])
  if(!isdigit(c_buf[1]) && !(c_buf[1] == 'B' || c_buf[1] == 'D')){

	  Serial.printlnf("TGWC must start with M[0-9], MB, or MD. char at 1 is: %c, ", c_buf[1]); 
	  return false;	  

  }