Saya mencari beberapa contoh sederhana dan praktik terbaik tentang cara menggunakan ekspresi reguler di ANSI C. man regex.h
tidak memberikan banyak bantuan.
Saya mencari beberapa contoh sederhana dan praktik terbaik tentang cara menggunakan ekspresi reguler di ANSI C. man regex.h
tidak memberikan banyak bantuan.
Jawaban:
Ekspresi reguler sebenarnya bukan bagian dari ANSI C. Sepertinya Anda mungkin berbicara tentang pustaka ekspresi reguler POSIX, yang dilengkapi dengan sebagian besar (semua?) * Nixes. Berikut adalah contoh menggunakan regex POSIX di C (berdasarkan ini ):
#include <regex.h>
regex_t regex;
int reti;
char msgbuf[100];
/* Compile regular expression */
reti = regcomp(®ex, "^a[[:alnum:]]", 0);
if (reti) {
fprintf(stderr, "Could not compile regex\n");
exit(1);
}
/* Execute regular expression */
reti = regexec(®ex, "abc", 0, NULL, 0);
if (!reti) {
puts("Match");
}
else if (reti == REG_NOMATCH) {
puts("No match");
}
else {
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
exit(1);
}
/* Free memory allocated to the pattern buffer by regcomp() */
regfree(®ex);
Atau, Anda mungkin ingin memeriksa PCRE , pustaka untuk ekspresi reguler yang kompatibel dengan Perl di C. Sintaks Perl cukup banyak dengan sintaks yang sama yang digunakan di Jawa, Python, dan sejumlah bahasa lainnya. Sintaks POSIX sintaks yang digunakan oleh grep
, sed
, vi
, dll
regcomp
, cflags
, adalah bitmask a. Dari pubs.opengroup.org/onlinepubs/009695399/functions/regcomp.html : "Argumen cflags adalah inklusif bitwise ATAU nol atau lebih dari bendera berikut ...". Jika Anda ATAU-bersama-sama nol, Anda akan mendapatkan 0. Saya melihat bahwa manual Linux untuk regcomp
mengatakan "cflags mungkin bitwise-atau dari satu atau lebih dari yang berikut", yang tampaknya menyesatkan.
regmatch_t matches[MAX_MATCHES]; if (regexec(&exp, sz, MAX_MATCHES, matches, 0) == 0) { memcpy(buff, sz + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so); printf("group1: %s\n", buff); }
perhatikan bahwa kecocokan grup mulai dari 1, grup 0 adalah seluruh string. Tambahkan cek kesalahan di luar batas, dll.
regfree
perlu setelah gagal regcomp
, meskipun itu agak kurang spesifik, ini menyarankan bahwa itu tidak boleh dilakukan: redhat.com/archives/libvir-list/2013-September/msg00276.html
Ini mungkin bukan yang Anda inginkan, tetapi alat seperti re2c dapat mengkompilasi POSIX (-ish) ekspresi reguler ke ANSI C. Ini ditulis sebagai pengganti lex
, tetapi pendekatan ini memungkinkan Anda untuk mengorbankan fleksibilitas dan keterbacaan untuk sedikit kecepatan terakhir, jika kamu benar-benar membutuhkannya.
man regex.h
melaporkan tidak ada entri manual untuk regex.h, tetapi man 3 regex
memberi Anda halaman yang menjelaskan fungsi POSIX untuk pencocokan pola.
Fungsi yang sama dijelaskan di Perpustakaan GNU C: Pencocokan Ekspresi Reguler , yang menjelaskan bahwa Perpustakaan GNU C mendukung antarmuka POSIX.2 dan antarmuka yang dimiliki Perpustakaan GNU C selama bertahun-tahun.
Misalnya, untuk program hipotetis yang mencetak string mana yang diteruskan sebagai argumen yang cocok dengan pola yang dilewati sebagai argumen pertama, Anda bisa menggunakan kode yang mirip dengan yang berikut.
#include <errno.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_regerror (int errcode, size_t length, regex_t *compiled);
int
main (int argc, char *argv[])
{
regex_t regex;
int result;
if (argc < 3)
{
// The number of passed arguments is lower than the number of
// expected arguments.
fputs ("Missing command line arguments\n", stderr);
return EXIT_FAILURE;
}
result = regcomp (®ex, argv[1], REG_EXTENDED);
if (result)
{
// Any value different from 0 means it was not possible to
// compile the regular expression, either for memory problems
// or problems with the regular expression syntax.
if (result == REG_ESPACE)
fprintf (stderr, "%s\n", strerror(ENOMEM));
else
fputs ("Syntax error in the regular expression passed as first argument\n", stderr);
return EXIT_FAILURE;
}
for (int i = 2; i < argc; i++)
{
result = regexec (®ex, argv[i], 0, NULL, 0);
if (!result)
{
printf ("'%s' matches the regular expression\n", argv[i]);
}
else if (result == REG_NOMATCH)
{
printf ("'%s' doesn't the regular expression\n", argv[i]);
}
else
{
// The function returned an error; print the string
// describing it.
// Get the size of the buffer required for the error message.
size_t length = regerror (result, ®ex, NULL, 0);
print_regerror (result, length, ®ex);
return EXIT_FAILURE;
}
}
/* Free the memory allocated from regcomp(). */
regfree (®ex);
return EXIT_SUCCESS;
}
void
print_regerror (int errcode, size_t length, regex_t *compiled)
{
char buffer[length];
(void) regerror (errcode, compiled, buffer, length);
fprintf(stderr, "Regex match failed: %s\n", buffer);
}
Argumen terakhir regcomp()
harus setidaknya REG_EXTENDED
, atau fungsi akan menggunakan ekspresi reguler dasar , yang berarti bahwa (misalnya) Anda perlu menggunakan a\{3\}
alih-alih a{3}
digunakan dari ekspresi reguler yang diperluas , yang mungkin adalah apa yang Anda harapkan untuk digunakan.
POSIX.2 juga memiliki fungsi lain untuk pencocokan wildcard: fnmatch()
. Itu tidak memungkinkan untuk mengkompilasi ekspresi reguler, atau mendapatkan substring yang cocok dengan sub-ekspresi, tetapi sangat spesifik untuk memeriksa kapan nama file cocok dengan wildcard (misalnya menggunakan FNM_PATHNAME
flag).
Ini adalah contoh penggunaan REG_EXTENDED. Ekspresi reguler ini
"^(-)?([0-9]+)((,|.)([0-9]+))?\n$"
Memungkinkan Anda untuk menangkap angka desimal dalam sistem Spanyol dan internasional. :)
#include <regex.h>
#include <stdlib.h>
#include <stdio.h>
regex_t regex;
int reti;
char msgbuf[100];
int main(int argc, char const *argv[])
{
while(1){
fgets( msgbuf, 100, stdin );
reti = regcomp(®ex, "^(-)?([0-9]+)((,|.)([0-9]+))?\n$", REG_EXTENDED);
if (reti) {
fprintf(stderr, "Could not compile regex\n");
exit(1);
}
/* Execute regular expression */
printf("%s\n", msgbuf);
reti = regexec(®ex, msgbuf, 0, NULL, 0);
if (!reti) {
puts("Match");
}
else if (reti == REG_NOMATCH) {
puts("No match");
}
else {
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
exit(1);
}
/* Free memory allocated to the pattern buffer by regcomp() */
regfree(®ex);
}
}
Meskipun jawaban di atas bagus, saya sarankan menggunakan PCRE2 . Ini berarti Anda benar-benar dapat menggunakan semua contoh regex di luar sana sekarang dan tidak harus menerjemahkan dari beberapa regex kuno.
Saya sudah membuat jawaban untuk ini, tapi saya pikir itu bisa membantu di sini juga ..
Regex In C Untuk Mencari Nomor Kartu Kredit
// YOU MUST SPECIFY THE UNIT WIDTH BEFORE THE INCLUDE OF THE pcre.h
#define PCRE2_CODE_UNIT_WIDTH 8
#include <stdio.h>
#include <string.h>
#include <pcre2.h>
#include <stdbool.h>
int main(){
bool Debug = true;
bool Found = false;
pcre2_code *re;
PCRE2_SPTR pattern;
PCRE2_SPTR subject;
int errornumber;
int i;
int rc;
PCRE2_SIZE erroroffset;
PCRE2_SIZE *ovector;
size_t subject_length;
pcre2_match_data *match_data;
char * RegexStr = "(?:\\D|^)(5[1-5][0-9]{2}(?:\\ |\\-|)[0-9]{4}(?:\\ |\\-|)[0-9]{4}(?:\\ |\\-|)[0-9]{4})(?:\\D|$)";
char * source = "5111 2222 3333 4444";
pattern = (PCRE2_SPTR)RegexStr;// <<<<< This is where you pass your REGEX
subject = (PCRE2_SPTR)source;// <<<<< This is where you pass your bufer that will be checked.
subject_length = strlen((char *)subject);
re = pcre2_compile(
pattern, /* the pattern */
PCRE2_ZERO_TERMINATED, /* indicates pattern is zero-terminated */
0, /* default options */
&errornumber, /* for error number */
&erroroffset, /* for error offset */
NULL); /* use default compile context */
/* Compilation failed: print the error message and exit. */
if (re == NULL)
{
PCRE2_UCHAR buffer[256];
pcre2_get_error_message(errornumber, buffer, sizeof(buffer));
printf("PCRE2 compilation failed at offset %d: %s\n", (int)erroroffset,buffer);
return 1;
}
match_data = pcre2_match_data_create_from_pattern(re, NULL);
rc = pcre2_match(
re,
subject, /* the subject string */
subject_length, /* the length of the subject */
0, /* start at offset 0 in the subject */
0, /* default options */
match_data, /* block for storing the result */
NULL);
if (rc < 0)
{
switch(rc)
{
case PCRE2_ERROR_NOMATCH: //printf("No match\n"); //
pcre2_match_data_free(match_data);
pcre2_code_free(re);
Found = 0;
return Found;
// break;
/*
Handle other special cases if you like
*/
default: printf("Matching error %d\n", rc); //break;
}
pcre2_match_data_free(match_data); /* Release memory used for the match */
pcre2_code_free(re);
Found = 0; /* data and the compiled pattern. */
return Found;
}
if (Debug){
ovector = pcre2_get_ovector_pointer(match_data);
printf("Match succeeded at offset %d\n", (int)ovector[0]);
if (rc == 0)
printf("ovector was not big enough for all the captured substrings\n");
if (ovector[0] > ovector[1])
{
printf("\\K was used in an assertion to set the match start after its end.\n"
"From end to start the match was: %.*s\n", (int)(ovector[0] - ovector[1]),
(char *)(subject + ovector[1]));
printf("Run abandoned\n");
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return 0;
}
for (i = 0; i < rc; i++)
{
PCRE2_SPTR substring_start = subject + ovector[2*i];
size_t substring_length = ovector[2*i+1] - ovector[2*i];
printf("%2d: %.*s\n", i, (int)substring_length, (char *)substring_start);
}
}
else{
if(rc > 0){
Found = true;
}
}
pcre2_match_data_free(match_data);
pcre2_code_free(re);
return Found;
}
Instal PCRE menggunakan:
wget https://ftp.pcre.org/pub/pcre/pcre2-10.31.zip
make
sudo make install
sudo ldconfig
Kompilasi menggunakan:
gcc foo.c -lpcre2-8 -o foo
Periksa jawaban saya untuk lebih jelasnya.