如何使用 Xcode 去除每行开头的非人类可读字符

how to strip out non-human-readable character at the start of each line using Xcode

提问人:Greg 提问时间:2/7/2023 最后编辑:Greg 更新时间:2/16/2023 访问量:110

问:

我正在尝试设置 Xcode 以摆脱从 1986 年创建的 8 英寸软盘中恢复的旧文本文件中的非人类可读字符。这些文件是在QDOS中创建的,QDOS是一种专有的磁盘操作系统,使用基于文本的音乐作曲语言应用程序(又名MCL)。

我的目标是编写一个 C 程序来逐个字符读取 ascii 文件,从源文件中过滤掉不可打印的字符并将其保存到目标文件,从而可以以与作曲家在 1986 年看到的格式完全相同的格式查看文件内容。

当 Xcode 读取旧文本文件时,不需要的字符将显示为除第一行之外的每一行的第一个人类可读字符。

    !B=24:Af
    *           BAR 1
    G2,6
     *           BAR 2 & 3
    !G2,1/4:Bf2,1/4:C2,1/4:Ef2,1/4:F3,1/4:G3,35/4:D3:A4
    "*           BAR 4 
    #Bf4:G4,2:D3:A4:Bf4
    $*           BAR 5
    %D4,2:C4,3:F5
    &*           BAR 6
    'D4:Bf4:A4,2:G4:D3:?
    (*           BAR 7 &

上述文本文件的十六进制转储显示两个 ascii 字节(回车符)后跟(文件分隔符)。这两个字节加上紧跟在它们后面的字节,是我试图删除的字符。$0D$1C

    0000: 1C 1D 21 42 3D 32 34 3A 41 66 0A 1C 1E 2A 20 20   ¿¿!B=24:Af¬¿¿*  
    0010: 20 20 20 20 20 20 20 20 20 42 41 52 20 31 0A 1C            BAR 1¬¿
    0020: 1F 47 32 2C 36 0A 1C 20 2A 20 20 20 20 20 20 20   ¿G2,6¬¿ *       
    0030: 20 20 20 20 42 41 52 20 32 20 26 20 33 0A 1C 21       BAR 2 & 3¬¿!
    0040: 47 32 2C 31 2F 34 3A 42 66 32 2C 31 2F 34 3A 43   G2,1/4:Bf2,1/4:C
    0050: 32 2C 31 2F 34 3A 45 66 32 2C 31 2F 34 3A 46 33   2,1/4:Ef2,1/4:F3
    0060: 2C 31 2F 34 3A 47 33 2C 33 35 2F 34 3A 44 33 3A   ,1/4:G3,35/4:D3:
    0070: 41 34 0A 1C 22 2A 20 20 20 20 20 20 20 20 20 20   A4¬¿"*          
    0080: 20 42 41 52 20 34 20 0A 1C 23 42 66 34 3A 47 34    BAR 4 ¬¿#Bf4:G4
    0090: 2C 32 3A 44 33 3A 41 34 3A 42 66 34 0A 1C 24 2A   ,2:D3:A4:Bf4¬¿$*
    00A0: 20 20 20 20 20 20 20 20 20 20 20 42 41 52 20 35              BAR 5
    00B0: 0A 1C 25 44 34 2C 32 3A 43 34 2C 33 3A 46 35 0A   ¬¿%D4,2:C4,3:F5¬
    00C0: 1C 26 2A 20 20 20 20 20 20 20 20 20 20 20 42 41   ¿&*           BA
    00D0: 52 20 36 0A 1C 27 44 34 3A 42 66 34 3A 41 34 2C   R 6¬¿'D4:Bf4:A4,
    00E0: 32 3A 47 34 3A 44 33 3A 3F 0A 1C 28 2A 20 20 20   2:G4:D3:?¬¿(*   
    00F0: 20 20 20 20 20 20 20 20 42 41 52 20 37 20 26 20           BAR 7 & 

我创建了一个 Xcode 项目。当我选择并在 Xcode 中时,可以看到相同的单个可打印字符。我选择了这些设置,因为我的 MacOS 期望 .Command Line ToolType : Plain TextText Encoding : Unicode (UTF-8)Inspectors Windowen_AU.UTF-8

后面的 C 代码将创建文本文件的相同副本,而无需标识单个字符。从本质上讲,它将读取旧文件内容并成功写入新文件。输出文件的十六进制转储与上面的十六进制转储相同。

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

    int main(int argc, const char * argv[]) {

    char filename[] = {"~/Desktop/MCLRead/bell1.ss"} ;

    printf("MCLRead\n\t%s\n", filename);

    FILE* fin = fopen(filename, "r");
    if (!fin) { perror("input error"); return 0; }

    FILE* fout = fopen("output.txt", "w");
    if (!fout) { perror("fout error"); return 0; }

    fseek(fin, 0, SEEK_END); // go to the end of file
    size_t filesize = ftell(fin); // get file size
    fseek(fin, 0, SEEK_SET); // go back to the beginning

    //allocate enough memory
    char* buffer = malloc(filesize * sizeof(char));

    //read one character at a time (or `fread` the whole file)

    size_t i = 0;
    while (1)
    {
        int c = fgetc(fin);
        if (c == EOF) break;

    //save to buffer
        buffer[i++] = (char)c;
    }

但是,当我在 Xcode 中编译、构建和运行它时,无论 Xcode 中的 or 设置如何,字符都是无法识别的。以下错误消息出现在TypeText EncodingInspectors WindowConsole Window

    error: No such file or directory
    Program ended with exit code: 0

当我在 中运行相同的代码时,它会生成一个输出文本文件,但字符无法识别Terminal Window

    Desktop % gcc main.c
    Desktop % ./a.out output.txt
    Desktop % cat output.txt                                           

cat导致终端中的字符串为 128 个字符 - 总共 128 个字符,即使文件总共包含一千多个字符。?Command Line

有人可以给我任何线索,使这个文本文件以一种允许从每行开头剥离非人类可读字符的格式可读。

请注意,我不是在寻求帮助编写 C 代码,而是在寻求什么文本格式将使不需要的 8 位字符可读,以便我可以删除它们(对我最初提出的问题略有改进)。任何进一步的帮助将不胜感激。提前致谢。


注意

本文已根据评论进行了修订。

十六进制转储是以文本而不是图像的形式完成的。这为任何想要测试我所做的事情的人提供了共享文本文件的最可靠方式


Xcode UTF-8 ASCII

评论

0赞 AmigoJack 2/9/2023
它不能替代 CR,因为十六进制 0D 已经是 CR。后面的字节每次出现都会增加:它以(第一行,不能低,因为它会与自身或类似)开头,最高字节在您的屏幕截图中(不带下划线)。它就像一个索引,可以快速知道我们在哪条线上。因此,文本文件不能容纳超过 227 行。1C1D1C0D32
0赞 Greg 2/9/2023
你可能是对的。我知道原来的 MCL 编辑器有自动行编号,文件分隔符 (IC) 后面的递增字符很可能用于对行进行编号。问题是如何将检索到的字符 IC 表示为 8 位,即 00011100。此字符在 UTF-8 文本编码中是 111000101001000010011100。在 Xcode 中,我找不到仅读取 8 位的文本编码。MacOS 终端窗口也使用 UTF-8。我做了一个编辑以进一步澄清。

答:

0赞 Greg 2/13/2023 #1

通过使用 not 将每个字节读取为 7 位二进制值,可以轻松解决该问题。源文件以十六进制读取,以十进制保存并读取为文本。intchar

注意。没有 EOF 字符。MCL 在文件末尾使用了“END”一词。由于它是从软盘映像中挽救出来的,因此在格式化时,该文件有时会在软盘上写入一个尾随的十六进制字符字符串。在其他时候,格式轨道已被覆盖,文件具有尾随的零字符串。E5

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

#define CR          0x0D                        // ASCII Carriage Return
#define FS          0x1C                        // ASCII File Separator
#define FD_FORMAT   0xE5                        // floppy disk format track

int main(int argc, const char * argv[]) 
{   
    char fname[20];
    printf("\n Enter MCL file name : ");
    scanf("%s", fname);
    printf("\n\t%s\n", fname);

    int a = 0;                                  // init CR holder
    int b = a;                                  // init File Separator holder
    FILE* fin = fopen(fname, "r");              // init read
    if (!fin) 
    { perror("input error"); return 0;
    }    
    FILE* fout = fopen("output.txt", "w");      // init write
    if (!fout) 
    { perror("fout error"); return 0; 
    }
    fseek(fin, 0, SEEK_END);                    // look for end of file
    size_t fsize = ftell(fin);                  // get file size
    fseek(fin, 0, SEEK_SET);                    // go back to the start                                             
    int* buffer = malloc(fsize * sizeof(int));  // allocate buffer                          
    size_t i = 0;
    while (1)
    {
        int c  = fgetc(fin);                    // read one byte at a time
        if (c  < CR)  break;                    // skip low control codes
        if (c == FD_FORMAT) break;              // skip floppy format track
        
        printf("\t%X", a);
        printf("\t%X", b);  

        if ((a != CR) && (b != FS))             // skip save if new line        
        {
        printf("\t%0X\n", c);
        buffer[i++] = c;                        // save to buffer   
        }                  
        a = b;
        b = c;
    }   
    for (i = 0; i < fsize; i++)                 // write out int by int
        fputc(buffer[i], fout);
    free(buffer);
    fclose(fin);
    fclose(fout);
    return 0;
}