提问人:Greg 提问时间:2/7/2023 最后编辑:Greg 更新时间:2/16/2023 访问量:110
如何使用 Xcode 去除每行开头的非人类可读字符
how to strip out non-human-readable character at the start of each line using Xcode
问:
我正在尝试设置 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 Tool
Type : Plain Text
Text Encoding : Unicode (UTF-8)
Inspectors Window
en_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 设置如何,字符都是无法识别的。以下错误消息出现在Type
Text Encoding
Inspectors Window
Console 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 位字符可读,以便我可以删除它们(对我最初提出的问题略有改进)。任何进一步的帮助将不胜感激。提前致谢。
注意
本文已根据评论进行了修订。
十六进制转储是以文本而不是图像的形式完成的。这为任何想要测试我所做的事情的人提供了共享文本文件的最可靠方式
答:
通过使用 not 将每个字节读取为 7 位二进制值,可以轻松解决该问题。源文件以十六进制读取,以十进制保存并读取为文本。int
char
注意。没有 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;
}
评论
0D
已经是 CR。后面的字节每次出现都会增加:它以(第一行,不能低,因为它会与自身或类似)开头,最高字节在您的屏幕截图中(不带下划线)。它就像一个索引,可以快速知道我们在哪条线上。因此,文本文件不能容纳超过 227 行。1C
1D
1C
0D
32