Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c语言中的字符串处理_C_String_Dialog - Fatal编程技术网

c语言中的字符串处理

c语言中的字符串处理,c,string,dialog,C,String,Dialog,我的程序的目标是通过一个字符串进行查看,并能够取出对话中的问题和答案 例如: (“你喜欢我吗?” (“是”(“我们是朋友”)) (“不”(“我恨你”)) ) 这个程序会去掉“你喜欢我吗?”并给你选择是或否的选项。一旦你选择了相应的选项,它会去掉“我们是朋友”或“我恨你” 有没有关于如何实现这一点的库或解决方案?如果我错了,请纠正我的错误,但是Lisp解析器可以很好地完成这项工作:P说真的,这看起来像是很好地用括号括起来的字符串列表或其他括号括起来的表达式。一个简单的递归解析器就足够了,只需创建一

我的程序的目标是通过一个字符串进行查看,并能够取出对话中的问题和答案

例如:
(“你喜欢我吗?”
(“是”(“我们是朋友”))
(“不”(“我恨你”))
)

这个程序会去掉“你喜欢我吗?”并给你选择是或否的选项。一旦你选择了相应的选项,它会去掉“我们是朋友”或“我恨你”


有没有关于如何实现这一点的库或解决方案?

如果我错了,请纠正我的错误,但是Lisp解析器可以很好地完成这项工作:P说真的,这看起来像是很好地用括号括起来的字符串列表或其他括号括起来的表达式。一个简单的递归解析器就足够了,只需创建一个数据结构,作为满足您需要的解析树即可

编辑:该死,我终于成功了。。。嗯,我必须承认,在晚上10点到12点之间正确地创建一个非常简单的解析器并不是一件简单的任务

/*
 * lrparser.c
 * LR-parser
 * A recursive Lisp-subset parser
 * that has a misleading name (it's not an LALR, but a recursive descent one).
 *
 * Originally written to answer
 * http://stackoverflow.com/questions/15371008/string-processing-in-c/
 *
 * Made in some *really* bored hours by Árpád Goreity (H2CO3)
 * on 12-03-2013
 *
 * Language: C99 (not sure if POSIX)
 */

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdarg.h>
#include <stdbool.h>

// AST node type
enum {
    NODE_STRING,
    NODE_LIST
};

// Permitted tokens
enum {
    TOKEN_INVALID   = -1,
    TOKEN_LPAREN    =  0,
    TOKEN_RPAREN,
    TOKEN_STRING,
    TOKEN_END
};

// Useful for debugging and error reporting
static const char *toknames[] = {
    "Left paren",
    "Right paren",
    "String",
    "End"
};

// ...Or simply an AST node...
struct ParseTree {
    int type; // string or list
    char *string; // if any
    struct ParseTree **children;
    size_t n_children;
};

// Construct a node structure from a type and any necessary data
static struct ParseTree *node_new(int type, ...)
{
    va_list args;
    va_start(args, type);
    struct ParseTree *node = malloc(sizeof(*node));
    assert(node != NULL);

    node->type = type;
    if (type == NODE_STRING) {
        /* If the node is a string, fill it
         * (ownership transfer: the argument will be
         * free()'d by the node_free() function)
         */
        node->string = va_arg(args, char *);
    }

    node->children = NULL;
    node->n_children = 0;

    va_end(args);

    return node;
}

void node_free(struct ParseTree *tree)
{
    switch (tree->type) {
    case NODE_STRING:
        free(tree->string);
        break;
    case NODE_LIST:
        for (int i = 0; i < tree->n_children; i++) {
            node_free(tree->children[i]);
        }
        free(tree->children);
        break;
    default:
        fprintf(stderr, "Warning: unknown node type %d\n", tree->type);
        break;
    }

    free(tree);
}

// Sorry, the usual logarithmic storage expansion is omitted for clarity
void node_add(struct ParseTree *parent, struct ParseTree *child)
{
    assert(parent != NULL);
    assert(child != NULL);

    parent->n_children++;
    parent->children = realloc(parent->children, sizeof(parent->children[0]) * parent->n_children);
    // Lazy error checking: assert() instead of compare to NULL
    assert(parent->children != NULL);
    parent->children[parent->n_children - 1] = child;
}

// Just in order to break thread safety
static const char *s = NULL; // the string to be parsed
static char *curstr = NULL; // the contents of the string value of the current token
static int curtok; // the current token

// The tokenizer
static int lex()
{
    // Whitespace doesn't matter
    while (isspace(s[0])) {
        s++;
    }

    // end of string
    if (s[0] == 0) {
        return TOKEN_END;
    }

    // The followin four are obvious
    if (s[0] == '(') {
        s++;
        return curtok = TOKEN_LPAREN;
    }

    if (s[0] == ')') {
        s++;
        return curtok = TOKEN_RPAREN;
    }

    if (s[0] == '"') {
        const char *begin = s;
        while (*++s != '"')
            ;

        size_t sz = s - begin - 2 + 1;
        curstr = malloc(sz + 1);
        memcpy(curstr, begin + 1, sz);
        curstr[sz] = 0;

        // skip trailing quotation mark (")
        s++;
        return curtok = TOKEN_STRING;
    }

    return curtok = TOKEN_INVALID;
}

void expect(int tok)
{
    if (curtok != tok) {
        fprintf(stderr, "Error: expected token %s, got %s\n", toknames[tok], toknames[curtok]);
        abort();
    }

    lex();
}

// a. k. a. "parse()"
// Simple recursive (one-level...) descent (root == list) approach
static struct ParseTree *recurse_and_descend()
{
    expect(TOKEN_LPAREN);       

    struct ParseTree *node = node_new(NODE_LIST);

    struct ParseTree *child;
    while (curtok != TOKEN_RPAREN) {
        if (curtok == TOKEN_LPAREN) {
            child = recurse_and_descend();
        } else if (curtok == TOKEN_STRING) {
            child = node_new(NODE_STRING, curstr);
            lex();
        } else {
            fprintf(stderr, "Unexpected token '%s'\n", toknames[curtok]);
            // lazy programmer's safety system, let the kernel do the dirty work
            abort();
        }
        node_add(node, child);
    }

    expect(TOKEN_RPAREN);

    return node;
}

static struct ParseTree *parse(const char *str)
{
    s = str; // poor man's initialization
    lex(); // The first breath of fresh token makes the baby's heart beat
    return recurse_and_descend(); // Let's do the Harlem shake!
}

// petite helper function
static void dump_indent(int indent)
{
    for (int i = 0; i < indent; i++) {
        printf("\t");
    }
}

// Because 0x7f502a00 is not very meaningful for the human eye
static void dump_tree(struct ParseTree *tree, int indent)
{
    dump_indent(indent);

    switch (tree->type) {
    case NODE_STRING:
        printf("<String \"%s\">\n", tree->string);
        break;
    case NODE_LIST:
        printf("<List>\n");
        for (int i = 0; i < tree->n_children; i++) {
            dump_tree(tree->children[i], indent + 1);
        }
        break;
    default:
        printf("Unknown node\n");
        break;
    }
}

int main(int argc, char *argv[])
{
    struct ParseTree *tree = parse(argv[1]);
    dump_tree(tree, 0);
    node_free(tree);

    return 0;
}
/*
*lrparser.c
*LR解析器
*递归Lisp子集解析器
*这有一个误导性的名称(它不是LALR,而是递归下降的名称)。
*
*原为答覆
* http://stackoverflow.com/questions/15371008/string-processing-in-c/
*
*由阿尔帕德·戈雷蒂(H2CO3)在无聊的几个小时内制作
*2013年3月12日
*
*语言:C99(不确定是否为POSIX)
*/
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
//AST节点类型
枚举{
节点_字符串,
节点列表
};
//准许代币
枚举{
令牌\u无效=-1,
令牌\u LPAREN=0,
代币,
令牌字符串,
令牌端
};
//用于调试和错误报告
静态常量字符*toknames[]={
“左帕伦”,
“对,帕伦”,
“字符串”,
“结束”
};
//…或者只是一个AST节点。。。
结构解析树{
int type;//字符串或列表
char*string;//如果有
结构解析树**子级;
儿童的大小;
};
//从类型和任何必要的数据构造节点结构
静态结构解析树*节点_新建(int类型,…)
{
va_列表参数;
va_启动(参数,类型);
struct ParseTree*node=malloc(sizeof(*node));
断言(节点!=NULL);
节点->类型=类型;
if(类型==节点\字符串){
/*如果节点是字符串,请填充它
*(所有权转让:争论将是
*free()'d由node_free()函数指定)
*/
node->string=va_arg(args,char*);
}
节点->子节点=NULL;
节点->n_子节点=0;
va_端(args);
返回节点;
}
void node_free(结构解析树*tree)
{
开关(树->类型){
案例节点\u字符串:
自由(树->字符串);
打破
案例节点列表:
对于(int i=0;in_子项;i++){
无节点(树->子节点[i]);
}
免费(树->儿童);
打破
违约:
fprintf(stderr,“警告:未知节点类型%d\n”,树->类型);
打破
}
自由(树);
}
//抱歉,为了清楚起见,通常的对数存储扩展被省略
void node_add(struct ParseTree*父节点,struct ParseTree*子节点)
{
断言(父级!=NULL);
断言(child!=NULL);
父项->n_子项++;
父级->子级=realloc(父级->子级,sizeof(父级->子级[0])*父级->n_子级);
//惰性错误检查:assert()而不是compare to NULL
断言(父级->子级!=NULL);
父->子项[父->n_子项-1]=子项;
}
//只是为了保证螺纹的安全
静态常量char*s=NULL;//要分析的字符串
静态字符*curstr=NULL;//当前标记的字符串值的内容
静态int-curtok;//当前令牌
//标记器
静态int-lex()
{
//空白不重要
while(isspace(s[0])){
s++;
}
//结束
如果(s[0]==0){
返回令牌(U端);
}
//以下四点是显而易见的
如果(s[0]=='('){
s++;
return curtok=TOKEN\u LPAREN;
}
如果(s[0]==')'){
s++;
return curtok=TOKEN\u RPAREN;
}
如果(s[0]==''''''){
const char*begin=s;
而(*++s!=“”)
;
大小_t sz=s-begin-2+1;
curstr=malloc(sz+1);
memcpy(curstr、begin+1、sz);
curstr[sz]=0;
//跳过尾随引号(“”)
s++;
return curtok=TOKEN\u字符串;
}
return curtok=TOKEN\u无效;
}
无效预期(int tok)
{
if(curtok!=tok){
fprintf(stderr,“错误:预期令牌%s,获得%s\n”,toknames[tok],toknames[curtok]);
中止();
}
lex();
}
//a.k.a.“parse()”
//简单递归(一级…)下降(根==列表)方法
静态结构解析树*递归和下降()
{
expect(TOKEN_LPAREN);
struct ParseTree*node=node\u new(node\u列表);
结构解析树*child;
while(curtok!=TOKEN\u RPAREN){
if(curtok==TOKEN\u LPAREN){
child=递归和下降();
}else if(curtok==TOKEN\u字符串){
child=node\u new(node\u字符串,curstr);
lex();
}否则{
fprintf(stderr,“意外令牌“%s”\n”,toknames[curtok]);
//懒惰程序员的安全系统,让内核做肮脏的工作
中止();
}
节点\添加(节点,子节点);
}
expect(TOKEN_RPAREN);
返回节点;
}
静态结构解析树*parse(const char*str)
{
s=str;//穷人的初始化
lex();//第一口新鲜的代币会让婴儿心跳
return recurse_and_down();//让我们来做哈莱姆摇动吧!
}
//小辅助函数
静态空转储缩进(整数缩进)
{
对于(int i=0;i类型){
案例节点\u字符串:
printf(“\n”,树->字符串);
h2co3-macbook:~ h2co3$ ./lrparser "(\"do you like me?\" (\"yes\" (\"we're friends\")) (\"no\" (\"i hate you\" \"me too\")) )"
<List>
    <String "do you like me?">
    <List>
        <String "yes">
        <List>
            <String "we're friends">
    <List>
        <String "no">
        <List>
            <String "i hate you">
            <String "me too">
QUESTION => '(' '"' TEXT '"' RESPONSES ')'
RESPONSES => null | RESPONSE RESPONSES
RESPONSE => '(' '"' TEXT '(' '"' TEXT '"' ')' ')'
TEXT => all characters except '(' '"' ')'