Input using sscanf with regular expression

2019-04-02 23:43发布

问题:

I want to take input of a particular part of a string like

"First (helloWorld): last"

From that string I want to take input only "helloWorld" by regular expression. I am using

%*[^(] (%s):"

But that does not serve my purpose. Please somebody help me to solve this problem.

回答1:

The format specifiers in the scanf family of functions are not generally considered to be a species of regular expression.

However, you can do what you want something like this.

#include <stdio.h>

int main() {
  char str[256];
  scanf("First (helloWorld): last", "%*[^(](%[^)]%*[^\n]", str);
  printf("%s\n", str);
  return 0;
}

%*[^(]   read and discard everything up to opening paren
(        read and discard the opening paren
%[^)]    read and store up up to (but not including) the closing paren
%*[^\n]  read and discard up to (but not including) the newline

The last format specifier is not necessary in the context of the above sscanf, but would be useful if reading from a stream and you want it positioned at the end of the current line for the next read. Note that the newline is still left in the stream, though.

Rather than use fscanf (or scanf) to read from a stream directly, it's pretty much always better read a line with fgets and then extract the fields of interest with sscanf

// Read lines, extracting the first parenthesized substring.
#include <stdio.h>

int main() {
  char line[256], str[128];

  while (fgets(line, sizeof line, stdin)) {
    sscanf(line, "%*[^(](%127[^)]", str);
    printf("|%s|\n", str);
  }

  return 0;
}

Sample run:

one (two) three
|two|
four (five) six
|five|
seven eight (nine) ten
|nine|


回答2:

Sorry, no true regular expression parser in standard C.

Using the format in the scanf() family is not a full-fledged regular expression, but can do the job. "%n" tells sscanf() to save the current scanning offset.

#include <stdio.h>
#include <stdlib.h>
char *foo(char *buf) {
  #define NotOpenParen "%*[^(]"
  #define NotCloseParen "%*[^)]"
  int start;
  int end = 0;

  sscanf(buf, NotOpenParen "(%n" NotCloseParen ")%n", &start, &end);
  if (end == 0) {
    return NULL; // End never found
  }
  buf[end-1] = '\0'; 
  return &buf[start];
}

// Usage example
char buf[] = "First (helloWorld): last";
printf("%s\n", foo(buf));

But this approach fails on "First (): last". More code would be needed.
A pair of strchr() calls is better.

char *foo(char *buf) {
  char *start = strchr(buf, '(');
  if (start == NULL)  {
    return NULL; // start never found
  }
  char *end = strchr(start, ')');
  if (end == NULL)  {
    return NULL; // end never found
  }
  *end = '\0'; 
  return &start[1];
}

Else one needs to use a not-part-of-the C-spec solution.



标签: c scanf