我设法从一个程序创建了以下输出:
7.86 ( 8Hm,), 6.82 ( 4Hm,),12.1 ( 1Hs,).
我想添加一个空格或删除一个空格,具体取决于我指向的字符。sscanf会允许你这样做吗?
我只是想知道在此文本中插入和删除空格的最简单方法是什么。例如,我想删除 (
和"num"(例如 8
(之间的空格,但在 H
和"字母"之间提供一个空格,例如 m
。到目前为止,我的代码看起来像这样:
typedef struct node {
int i;
char array[SIZE];
struct node* link;
} node;
node* format(void)
{
int count = 0;
int size = list_size(data, sizeof(data)) / 4;
for (node* ptr = head; ptr != NULL; ptr = ptr->link)
{
int i;
int j;
for (i = 0, j = 0; i < sizeof(ptr->array); i++, j++)
{
if (ptr->array[0] == ' ' && count == 0)
{
count++;
j--;
}
else if (ptr->array[i] == ' ' && ptr->array[i-1] == '.')
{
j--;
ptr->array[i] = ',';
}
else if (ptr->array[i] == ',' && ptr->array[i-1] == ')')
{
if (count == size)
{
ptr->array[i] = '.';
}
}
ptr->array[j] = ptr->array[i];
}
count++;
}
return head;
}
请注意,上面目前是一个大小为 3 的链表,我创建了后者以启用字符"组"的交换,然后以特定方式颠倒顺序。如果我先将所有内容传递回单个数组,格式化会更容易吗?
任何提示/建议将不胜感激!
最简单的方法是使用 sscanf
正确解析字符串,然后将其打印到另一个字符串。以您正在执行的方式手动解析字符串不会给您带来可观察到的速度/内存增益,只会添加大量代码。
例
#include<stdio.h>
int main(){
char str[]= "7.86 ( 8Hm,), 6.82 ( 4Hm,),12.1 ( 1Hs,).";
float f1, f2, f3;
int i1, i2, i3;
sscanf(str, "%f ( %dHm,), %f ( %dHm,),%f ( %dHs,).", &f1, &i1, &f2, &i2, &f3, &i3);
printf("%f ( %dHm,), %f ( %dHm,),%f ( %dHs,).n", f1, i1, f2, i2, f3, i3);
return 0;
}
scanf
函数功能强大,如您所见,您可以使用它们来解析格式化的字符串。运行此示例中的代码时,它会打印以下内容:
7.860000 ( 8Hm,), 6.820000 ( 4Hm,),12.100000 ( 1Hs,).
它的工作方式是scanf
可以忽略字符。因此,它读取第一个浮点数,然后忽略空格,忽略括号,读取整数,忽略 Hm 等等。
我的printf
是按照与输入相同的方式格式化字符串。您可以对其进行调整以满足您的要求。您还应该四处搜索并限制十进制数字。但基本思想是,您可以从字符串中获取所需的数据,然后可以按照所需的方式打印该数据。
尽最大努力了解您当前在ptr-array
中的内容,然后如何完成重新格式化,您似乎想要这样做in-place
简单地更新ptr->array
以保持更新的格式化字符串,然后您可以构建一个格式正确的缓冲区来替换当前ptr->array
。
注意:更好的解决方案是将ptr->array
中的值分成实际的单独值,并将其作为链表的一部分,您可以在其中静态声明一个结构数组来保存您的values
和units
(这是我对7.86 (8Hm,)
的最佳猜测。这将允许您以任何需要的方式格式化值,而不是停留在array
中的内容。例如:
#define USIZE 8
typedef struct values {
double value;
char[USIZE];
} values;
typedef struct node {
int i;
char array[SIZE];
values *vals;
struct node* link;
} node;
或者,例如:
typedef struct node {
int i;
char array[SIZE];
values vals[3];
struct node* link;
} node;
无论如何,您最初的问题是如何重新格式化现有ptr->array
删除'('
后面的空格并将'8Hm'
分隔到以下示例数据中'8H m'
:
7.86 ( 8Hm,), 6.82 ( 4Hm,),12.1 ( 1Hs,).
假设您正在迭代列表中的每个节点,则此重新格式化可能仅在收集/存储所有节点后运行一次。一种方法是以新格式构造一个新的缓冲区保存array
,然后将新array
替换为格式正确的buffer
。
有很多方法可以做到这一点,但是如果您的重新格式化条件有限,只需使用久经考验的英寸蠕虫方法用指针向下走array
,用所需格式的字符填充新缓冲区就像其他任何东西一样简单和灵活。
下面,该示例创建一个新的缓冲区(buf[SIZE]
(从ptr->array
中复制/替换/删除字符,然后将ptr->array
替换为buf
的内容。
注意:我没有在任何数据上运行它,所以您可能需要稍微调整一下逻辑。这只是为了向您展示一种可以使用的方法,并使其尽可能接近您的问题的解决方案(据我所知(。
注2:如果您不限于特定的标头,则可以将下面的大写/小写条件替换为isupper
或islower
from ctype.h
。此外,下面的memcpy
将需要string.h
,但如果这是一个问题,可以重写以简单地在没有它的情况下进行复制。
node* format(void)
{
/* for each node in list */
for (node* ptr = head; ptr != NULL; ptr = ptr->link)
{
/* declare a pointer to `ptr->array` and `buf` */
char *p = ptr->array;
char *pend = p + SIZE;
char buf[SIZE] = {0};
char *bp = buf;
/* for each char in ptr->array */
while (p < pend)
{
/* if not the first char */
if (p > ptr->array)
{
/* if current char is ' ' */
if (*p == ' ')
{
/* if previous char is one of the following */
if (*(p - 1) == '.') *bp++ = ',';
if (*(p - 1) == ')') *bp++ = '.';
if (*(p - 1) == '(') { p++; continue; } /* remove ' ' after '(' */
}
/* if current is lower case & prior is upper, separate */
else if (('a' <= *(p - 1) && *(p - 1) <= 'z') && ('A' <= *p && *p <= 'Z'))
{
*bp++ = ' ';
*bp++ = *p;
}
/* default - copy current to buf */
else
*bp++ = *p;
}
p++; /* advance to next char */
}
/* copy formatted string to ptr->array */
memcpy (ptr->array, buf, SIZE);
}
return head;
}
注3:如果SIZE
是全局#define
,则将sizeof (ptr->array)
替换为SIZE
。