将文本文件中的小写字符转换为大写字母和反之亦然

时间:2017-10-12 16:59:41

标签: c file io

我有一个包含以下文字的文字文件,没有换行符......

Hello World

我想将小写字符转换为大写字母,反之亦然,以便相同的文本文件最终会显示以下文字......

hELLOW wORLD

不幸的是,当我运行我的代码时,它会进入无限循环。当我逐步执行代码时,我看到fseek()返回第一个循环的一个字节,正如预期的那样,但它会返回第二个和后续循环的两个字节。我不明白为什么它会返回两个字节而不是一个字节。为什么会这样?有人可以帮忙吗?

这是我的代码......

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

int main()
{
    FILE *fp;
    int ch;
    long offset;

    fp = fopen("c:\\users\\domenic\\desktop\\test.txt", "r+");
    if (fp == NULL)
    {
        printf("error:  unable to open file\n");
        exit(1);
    }

    offset = ftell(fp);
    while (1)
    {
        ch = fgetc(fp);
        if (ch == EOF)
            break;
        if (isupper(ch))
        {
            fseek(fp, offset, SEEK_SET);
            fputc(tolower(ch), fp);
        }
        else if (islower(ch))
        {
            fseek(fp, offset, SEEK_SET);
            fputc(toupper(ch), fp);
        }
        offset = ftell(fp);
    }

    fclose(fp);

    return 0;
}

2 个答案:

答案 0 :(得分:1)

如果我了解您只想在整个文件中将 upper 更改为 lower 并将 lower 更改为 upper ,你可能会让自己变得比你需要的更难。

在我们研究一种让事情变得更容易的方法之前,让我们谈谈在代码中避免幻数硬编码路径。 C为main提供了一个定义,允许您为代码提供参数以避免硬编码值(例如文件/路径名) - 使用它们。使用参数正确调用main是:

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

(或者您会看到等效的int main (int argc, char **argv)

不带参数的调用是int main (void)

现在回答手头的问题。正如我在评论中所提到的,在处理ASCII时,控制案例的是第6位 - 从讨论中,如果你正在处理EBCDIC,那么* case-bit {{ 1}} A ^ a is the 7th-bit. As @chux pointed out both can be handled seamlessly by determining the appropriate bit 32 for both (the result is(1 <&lt; 5), e.g. 64 for ASCII, and(1 <&lt; 6)or( A-Za-z)for EBCDIC. To toggle any bit on/off you simply XOR the *case-bit* with the current character'c'. So far any character A ^ a`,例如

, you wish to toggle the case of, you simply XOR it with

如果if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) c ^= A ^ a; 为大写,则现在为小写,反之亦然。

为整个文件执行此操作,将文件名转换为程序的第一个参数(如果没有给出参数,则默认从c读取)并输出生成的case转换为{{ 1}},你可以做一些简单的事情:

stdin

示例输入

stdout

示例使用/输出

#include <stdio.h>

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

    int c;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

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

    while ((c = fgetc(fp)) != EOF)          /* read each char */
        /* is it a letter ? */
        if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))
            putchar (c ^ ('A' ^ 'a'));      /* toggle case */
        else
            putchar (c);                    /* just output */

    if (fp != stdin) fclose (fp);    /* close file if not stdin */

    return 0;
}

如果要将输出写入新文件,只需重定向输出,例如

$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.

将case转换的输出写入$ ./bin/case_toggle < dat/captnjack.txt tHIS IS A TALE oF cAPTAIN jACK sPARROW a pIRATE sO bRAVE oN THE sEVEN sEAS.

仔细看看,如果您有其他问题,请告诉我。

答案 1 :(得分:0)

首先,在使用fseek返回1个字符后,fputc不会删除或更像是“插入”。

在这种情况下,你是:

  1. 得到一个字符
  2. fseek to the char
  3. 在步骤2中找到的字符之前放置大写/小写字符
  4. 在新角色后设置新的偏移量。
  5. 退出无限循环后,你的文本文件中可能会有很多hEEEEEEEEEEEEEEEEEE?

    为了解决这个问题,我会创建一个临时的新文件......就像这样:

    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    int main()
    {
        FILE *fp, *new_f;
        int ch;
        long offset;
    
        fp = fopen("test.txt", "r+");
        new_f = fopen("test2.txt", "w" );
    
        if ( fp == NULL || new_f == NULL )
        {
            printf("error:  unable to open file\n");
            exit(1);
        }
    
        offset = ftell(fp);
        while (1)
        {
            ch = fgetc(fp);
    
            if (ch == EOF)
                break;
    
            if( !isalpha( ch ) )
            {
                fputc( ch, new_f );
            }
            else if (isupper(ch))
            {
                fputc(tolower(ch), new_f );
            }
            else if (islower(ch))
            {
                fputc(toupper(ch), new_f);
            }
        }
    
        fclose( fp );
        fclose( new_f );
    
        return 0;
    }