将文本存储在数组中的两个字符之间

Store text between two characters in a array

我有这个字符数组 char txt[80] = "Some text before /01/2017$"; 并且需要将两个 $ 之间的内容复制到一个字符串 11/01/2017 中。我如何使用 <string.h> 函数执行此操作?

假设您确定字符串中有 2 个 $...您可以执行以下操作:

char *first_dollar = strchr(txt, '$'); //get position of first dollar from the start of string
char *second_dollar = strchr(first_dollar + 1, '$'); //get position of first dollar starting
                                                    // from one position after the first dollar
char tocopy[20];
*second_dollar = '[=10=]'; //change the value of last dollar to '[=10=]'
strcpy(tocopy, first_dollar + 1); //copy into the place you want
*second_dollar = '$'; // put back the second dollar

如果您不确定字符串中是否包含 2 $,您应该检查 strchr 的 return,即 NULL.

是否必须使用字符串?有一个聪明的方法使用 sscanf:

char txt[80] = "Some text before /01/2017$";
char t[20];
sscanf(txt, "%*[^$]$%[^$]", t);
printf("ORIGINAL TEXT: %s\nEXTRACTED TEXT: %s\n", txt, t);

scanf中的格式含义如下:

  1. 忽略所有不是 $;
  2. 的字符
  3. 忽略 1 $
  4. 读取所有字符,直到找到下一个 $ 并将其存储在 t 中。

我不知道你为什么要用string.h。

供您参考,这没有 string.h 方法。

更新

#include <stdio.h>
#include <string.h>
int main(){
  char txt[80] = "Some text before /01/2017$ and /01/2017$ and $$ end $abc$";
  char get[80] = { '[=10=]' };
  int i = 0, k = -1, j = 0;
  int len = strlen( txt ); // Get length
  for ( i = 0 ; i < len ; i++ ){
    bool   find = false;
    for ( i  ; txt[i] != '$' && txt[i] != '[=10=]' ; i++ ); // Find '$' location
      if ( txt[i] == txt[i+1] && txt[i] == '$' ) { // Check $$ case
        find = true;
        get[++k] = ' ';
      } // if
      for ( j = i + 1 ; txt[j] != '$' && txt[j] != '[=10=]' ; j++ ){
        find = true;
        get[++k] =  txt[j];
      } // for

   if ( find == true ) get[++k] = ' '; // add space
    i = j ;
  } // for

  get[k] = '[=10=]'; // remove last space
  printf( "%s", get );
  return 0;
} // main()

输出:

21/01/2017 32/01/2017   abc

提取 $

之间的文本

这可以通过简单的 for 循环、读取和复制字符来完成。
在下面的代码中,参数 inside 表示我们当前是否在两个 $

之间

函数returns 1 if two $ were effective found

#include <stdio.h>
#include <string.h>

// return 1 if two $ have been found, 0 elsewhere
int extract (char *in, char *out, char c) {
    if (in == NULL) return 0;
    int size = strlen(in);
    int inside = 0;
    int n = 0;      // size new string
    for (int i = 0; i < size; ++i) {
        if(in[i] == c) {
            if (inside) {
                inside = 2;
                break;  // 2nd $
            }
            inside = 1;         // 1st $
        } else {
            if (inside) {       // copy
                out[n++] = in[i];
            }
        }
    }
    out[n++] = '[=10=]';
    return inside == 2;
}

int main() {
    char txt[80] = "Some text before /01/2017$";
    char txt_extracted[80];
    int check = extract (txt, txt_extracted, '$');
    if (check) printf ("%s\n", txt_extracted);
    else printf ("two $ were not found\n");
    return 0;
}

有一个函数叫做 strtok。 (https://www.cplusplus.com/reference/cstring%20/strtok/) 这是一个关于它的视频:https://www.youtube.com/watch?v=34DnZ2ewyZo.

我试过这段代码:

#include <stdio.h>
#include <string.h>

int main()
{
    char txt[] = "Some text before /01/2017$, some text, /04/2018$ another text more and more text /02/2019$";
int skip = 0;

char* piece = strtok(txt, "$");

while(piece != NULL)
{
    piece = strtok(NULL, "$");

    if(piece == NULL)
        break;

    if(skip != 1)
    {
        skip = 1;    
        printf("%s \n", piece);
    }
    else
        skip = 0;
    
}

    return 0;
}

输出:

11/01/2017
11/04/2018
01/02/2019

这是一个函数。无把手井边角案例。使用 string.h 函数。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char *texBetween(const char *str, char ch)
{
    char *result = NULL;
    const char *start, *end;

    if(str)
    {
        start = strchr(str, ch);
        if(start)
        {
            end = strchr(start + 1, ch);
            if(end)
            {
                result = malloc(end - start);
                if(result)
                {
                    memcpy(result, start + 1, end - start - 1);
                    result[end - start] = 0;
                }
            }
        }
    }
    return result;
}

int main()
{
    char *result;
    printf("\"%s\"\n", (result = texBetween("$$", '$')) ? result : "ERROR"); free(result);
    printf("\"%s\"\n", (result = texBetween("$ $", '$')) ? result : "ERROR"); free(result);
    printf("\"%s\"\n", (result = texBetween("$test$", '$')) ? result : "ERROR"); free(result);
    printf("\"%s\"\n", (result = texBetween("test$$", '$')) ? result : "ERROR"); free(result);
    printf("\"%s\"\n", (result = texBetween("test$test1$", '$')) ? result : "ERROR"); free(result);
    printf("\"%s\"\n", (result = texBetween("test34$test$dfd", '$')) ? result : "ERROR"); free(result);
    printf("\"%s\"\n", (result = texBetween(NULL, '$')) ? result : "ERROR"); free(result);
    printf("\"%s\"\n", (result = texBetween("", '$')) ? result : "ERROR"); free(result);
    printf("\"%s\"\n", (result = texBetween("$", '$')) ? result : "ERROR"); free(result);

}

https://godbolt.org/z/K5P6zb

获得不修改原始字符串的单个标记的简单方法是使用两次调用 strcspn() 建立指向第一个分隔符的起始指针(在本例中为 '$')和指向标记中最后一个字符的结束指针(第二个 '$' 之前的字符或字符串结尾,如果没有第二个 '$' 存在)。然后验证起始指针和结束指针之间是否存在字符,并使用 memcpy() 复制令牌。

一个简短的例子是:

#include <stdio.h>
#include <string.h>

int main (void) {
    
    char txt[80] = "Some text before /01/2017$",
        *sp = txt + strcspn (txt, "$"),                 /* start ptr to 1st '$' */
        *ep = sp + strcspn (*sp ? sp + 1 : sp, "$\n"),  /* end ptr to last c in token */
        result[sizeof txt] = "";                        /* storage for result */
    
    if (ep > sp) {                                      /* if chars in token */
        memcpy (result, sp + 1, ep - sp);               /* copy token to result */
        result[ep - sp] = 0;                            /* nul-termiante result */
        printf ("%s\n", result);                        /* output result */
    }
    else
        fputs ("no characters in token\n", stderr);
}

(注意: 三进制 只是处理 txt 是空字符串的情况。 '\n' 作为第二个定界符的一部分添加,以处理从 fgets() 或 POSIX getline() 过去的字符串,其中没有第二个 '$' 并且 '\n' 是最后一个字符在字符串中。)

也适用于空字符串、零、一或两个 '$' 的任意组合,并且不会修改原始字符串,因此可以安全地与 String-Literals 一起使用。

例子Use/Output

$ ./bin/single_token
11/01/2017

如果您还有其他问题,请告诉我。


允许有效空字符串作为结果的变体

@chqrlie 提供的巧妙改进提供 (*sp == '$') 而不是 (ep > sp) 的测试将允许空字符串(令牌中没有字符)成为有效结果 --我同意)。更改为:

    if (*sp == '$') {                                   /* if chars in token */
        memcpy (result, sp + 1, ep - sp);               /* copy token to result */
        result[ep - sp] = 0;                            /* nul-termiante result */
        printf ("%s\n", result);                        /* output result */
    }

因此,如果您想将空标记(如 .csv 中的空字段,例如 "one,,three,four")视为有效标记,请使用此替代方法。