【问题标题】:How can I parse out only the last character of a string?如何仅解析字符串的最后一个字符?
【发布时间】:2016-04-25 11:53:06
【问题描述】:

我目前的工作是从输入的 mp3 字符串中解析出歌曲名称和艺术家。

字符串的格式为“artist-title.mp3”,我们的老师向我们提供了此信息并确保任何歌曲名称中都没有-字符,但可能有也可能没有标题中的 . 字符。

我现在写的方式与strtok() 函数完美配合,只抓取这些字符之前的内容并将它们放入标题/艺术家字段。

像这样:

//Parse out the artist and title from the song
    char* artistName = strtok(song, "-");
    char* songName = strtok(NULL, ".");

    //Allocate a new block of memory to the blocks songInfo fields with the correct size
    newBlock->songInfo.artist = (char*)malloc(sizeof(char) * strlen(artistName) + kNullTerminator);
    newBlock->songInfo.title = (char*)malloc(sizeof(char) * strlen(songName) + kNullTerminator);

唯一的问题是如果标题名称中有一个点,它不会将完整的字符串识别为标题,它会切断它。我想知道的是如何使用strtok() 获得最后一个. 而不仅仅是它找到的第一个点?

【问题讨论】:

  • 是 C 还是 C++?
  • 如果 C++ std::string::find_last_of()
  • C++ -> std::string. C C++?
  • malloc() 的明显用法指出这可能与 C 有关。
  • @SouravGhosh:你是个相当乐观的人,不是吗? ;-) 也许没有说明相关语言的问题应该以“太宽泛”来结束。

标签: c++ c string parsing strtok


【解决方案1】:

首先,您可以利用strrchr() 找出输入中最后出现的.

也就是说,使用strtok(),您也可以完成这项工作。继续解析相同的字符串,直到你得到 NULL,然后考虑最后但一次的情况。

【讨论】:

  • strrcr 是要走的路。我认为 strtok 将通过将点设置为零字节来破坏标题,这似乎不是作者想要的
  • 注意到,但这只是意味着如果他确实有一个中间标题'.',则由 OP 将这些部分(个人 strtok 返回)放在一起。
【解决方案2】:

实际上,使用strtok 可能会使事情变得比实际需要的更难。如果您的老师告诉您字符串格式为 artist-title.mp3 并保证字符串中只有一个 '-'(即分隔符),那么您已经拥有将字符串解析为所需的所有信息artisttitle 没有strtok

考虑一下。您需要做的就是阅读每一行。您首先要确认该行以.mp3 结尾,并且该行至少为8 字符长(如果使用面向行的 输入函数,如fgetsgetline )。为什么?

 a - a . m p 3 \n
+-+-+-+-+-+-+-+-
 1 2 3 4 5 6 7 8

如果该行少于 8 字符,则不能有 artist、分隔符、title.mp3(带有尾随换行符)。您可以通过简单地调用strlen 来获得长度。您可以通过从line[len-5] 开始简单地调用strncmp 来确认字符串的最后4 个字符是.mp3

接下来您要确认该行包含'-' 分隔符。对strchr 的简单调用既可以确认存在,也可以返回指向行内分隔符位置的指针。

知道了行的长度和'-' 分隔符的位置,你的行已经被解析了。您需要做的就是nul-terminate'-' 分隔符和'.'(在.mp3 中)处的字符串部分,并将这些部分复制到您的存储中以供artisttitle

在一个简单的示例中将各个部分组合在一起,您可以执行以下操作:

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

typedef struct {
    char *artist;
    char *title;
} track;

enum { MAXS = 128, MAXC = 256 };

int main (int argc, char **argv) {

    track album[MAXS] = {{NULL}, {NULL}};
    char line[MAXC] = {0};
    size_t i, idx = 0;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {
        fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
        return 1;
    }

    while (fgets (line, MAXC, fp)) 
    {
        char *p = strchr (line, '-');       /* pointer to '-'    */
        size_t len = strlen (line);         /* length of line    */

        if (!p || len < 8 || strncmp (&line[len-5], ".mp3", 4))
            continue;                       /* skip invalid line */

        *p = 0;                             /* nul-terminate at '-' */
        line[len-5] = 0;                    /* nul-terminate at '.' */

        album[idx].artist = strdup (line);  /* alloc/copy artist */
        album[idx++].title = strdup (p + 1);/* alloc/copy title  */

        if (idx == MAXS) {  /* check index against max songs */
            fprintf (stderr, "warning: MAXS songs reached.\n");
            break;
        }
    }

    printf ("\nArtists & Titles\n");
    for (i = 0; i < idx; i++)
        printf ("\n artist : %s\n title  : %s\n",
                album[i].artist, album[i].title);

    for (i = 0; i < idx; i++) {
        free (album[i].artist);
        free (album[i].title);
    }

    return 0;
}

示例输入文件

$ cat dat/artist-title.txt
This is a collection of songs artist-title in mp3 format

# favorite artists
SO Superband-Against the String.mp3
# a capella
.30 Caliber Quartet-Songs to Die For.mp3
# duets
Dot.com.duet-Internet Harmony.mp3

输出

$ ./bin/fgets_artist_title dat/artist-title.txt

Artists & Titles

 artist : SO Superband
 title  : Against the String

 artist : .30 Caliber Quartet
 title  : Songs to Die For

 artist : Dot.com.duet
 title  : Internet Harmony

您可以添加额外的验证来防止短读,或检查大写的.MP3 等,但对于基本逻辑,您不能比仅使用您的信息更简单给出了所涉及的长度和一个指针。如果您有任何问题,请告诉我。

【讨论】:

    猜你喜欢
    • 2014-02-12
    • 1970-01-01
    • 2013-01-10
    • 1970-01-01
    • 2011-07-07
    • 2011-08-17
    • 2022-06-17
    相关资源
    最近更新 更多