copy and paste word into Scanf

Discussion in 'Mac Programming' started by larswik, Feb 26, 2011.

  1. larswik macrumors 68000

    Joined:
    Sep 8, 2006
    #1
    Today I had to do some work and write 4 small script for a commercial I am working on. The client sent me 4 scripts he liked all written in UPPER CASE and hard to read. Perfect for me to step out of Pascal and into C for the afternoon (refresher in C).

    PROJECT - To write a console based algorithm where I can convert upper case text to lower case text.

    The Method I would like to do is to copy from my text document and paste a string with white spaces in to the input buffer. Then populate the char array with string from the buffer. I would use the STRLEN (Or Similar) to get a char array count, with white spaces. Then use a loop to convert the upper to lower case and write out the final result.

    There are 2 points that I had a problem with when I started. Copying and pasting a string to the input buffer and getting STRLEN to see white spaces. "ABC" STRLEN was 3 and "ABC D" was also 3. It was seeing the white space as the string terminator.

    Thanks!

    -Lars
     
  2. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #2
    You won't be able to use scanf for this because, as you've observed, a %s in scanf will stop inputting at the first whitespace.

    Use fgets instead. Here's a simple echo program that uses fgets.

    Code:
    #include <stdio.h>
    
    int main(int argc, const char* argv[])
    {
    
        const int maxInput = 100;
    	
        /* Allocate the input buffer */
        char inputBuffer[maxInput];
    	
        /* Infinite loop, but see below :) */
        for (;;) {
    		
            /* Read a line of input into the input buffer */
            char* r = fgets(inputBuffer, maxInput, stdin);
    		
            /* If EOF or IO error, gets returns NULL, 
               so break out of the loop */
            if (r == NULL) break;
    		
            /* Output the input Buffer */
            printf("%s", inputBuffer);
    		
            /* Loop back to read and print another line of input */
        }
    	
        /* Cya */
        return 0;
    	
    }
    
     
  3. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #3
    Thanks! I will try to use the fgets to read in the input buffer.
     
  4. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #4
    There's one subtle difference between scanf("%s") and fgets. fgets will include the newline character in inputBuffer which scanf("%s") doesn't do.

    For example, if you enter ABC, the inputBuffer will contain { 'A', 'B', 'C', '\n', '\0' }. So strlen(inputBuffer) for this example would be 4 and not 3 because of this newline character. Just use strlen(inputBuffer) - 1 instead of strlen(inputBuffer).

    There's an edge case that occurs when nothing is entered, only return is pressed. There's another edge case the occurs when maxInput or more characters are entered. Avoid doing those two things.
     
  5. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #5
    I was testing the fgets and I can not get it to except a string that was pasted into the buffer. It would print out nothing. But when I manually enter the string from the keyboard it printed fine. Here is the simple test script

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main (int argc, const char * argv[]) {
    
    	int maxSize = 200;
    	char inputBuffer[maxSize];
    
    	
    	printf("Paste or type line here: ");
    	
    	fgets(inputBuffer, maxSize, stdin);
    
    	printf("Line is %s\n", inputBuffer); // Testing output..
    	
        return 0;
    }
    Perhaps I need to create a loop as you had in your example to populate the char array but I would think if that were the case the first character of what ever you pasted would go into ARRAY[0], but nothing write out to the screen.
     
  6. jiminaus, Feb 26, 2011
    Last edited: Feb 26, 2011

    jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #6
    I cannot reproduce your problem. When I copy and paste from a text editor (TextMate in my case) into the terminal it works fine.

    The loop just allows you to enter and process multiple lines of input without re-running the program.

    Are you pasting into Terminal, or the debugger in Xcode?

    EDIT: When I tried in this in the debugger console in XCode, I had to press Return before the fgets would return, and then all the lines were taken as one line. Looks like the debugger console is stripping out the newlines of pasted text.
     
  7. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #7
    Thanks for your help! I went a different way where I just paste it into the code before I run it. The goal was to work on the my money making job and thought I cold work some code into it to convert the all upper case. I then just copied the printed results and and pasted it right back.

    -Lars
     
  8. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #8
  9. Bill McEnaney, Feb 27, 2011
    Last edited: Feb 27, 2011

    Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #9
    I might do it this way.

    I'm calling fputs() because I like to use the most specific function that will do the job I need it to do. I've heard that fputs() outruns printf() because fputs() is for strings only.
    Code:
    while (fgets(inputBuffer, sizeof(inputBuffer), stdin) != NULL)
       fputs(inputBuffer, stdout);
     
  10. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #10
    GCC actually turns printf("%s", *pt) into puts(*pt) by default.
     
  11. Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #11
    That's good. But I think I'll use puts or fputs anyway because other compilers may keep the printf in the program.
     
  12. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #12
    Grrr, I so hate this code pattern and C's culture of one-liners. -2 for maintainability, -2 for debugability, -1 for readibility, 0 for performance. The only +1 seems to be showmanship. I don't give it a +1 for time saving, because all it does is shift the time burden onto someone else later.

    (I'm talking about the code pattern and not the use of fputs).
     
  13. Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #13
    Who's showing off? Not me. I'll bet you'll find the same pattern in K&R, where you'll see something like this, too.
    Code:
    while (*dest++ = *src++)
       ; 
    That loop copies the source string to the destination one. But I don't care for it because there's no boolean expression between the loop's parentheses. I would have used strcpy instead.
     
  14. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #14
    Will the fputs allow me to copy an entire 90 word document and populate a new char array? The problem that I came across was the paste process. It seems like the things I tried had to be input from the keyboard for it to correctly populate the char array.

    The only way I thought I could do this was to double back in the C book to read and write to files and read in the test one char at a time. I just read through that chapter and did not try to code anything.

    -Lars
     
  15. Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #15
    Everyone, I'm confused about what Lars wants his program to do for him. At first, I thought it needed only covert each capital letter in a file to a lowercase letter. Then I wondered why a document in all lowercase letters would be more human-readable than one in all capital letters. Should our friend's program still capitalize the first word of each sentence or the first letter of each proper noun? Will the program store the lowercase letters in another file or change the original file?

    If Lars just wants to fill a character array, maybe it's best to read the 90 words character by character. Maybe Lars can revise jinianus's program to make it call strcat to create a huge string of the ones that program reads with fgets. But how do we know how long the huge string could get if Lars plans to reuse the program he's writing? Does the C99 Standard limit the maximum length of a string?

    My while loop that jimianus criticized only copies lines of text from stdin to stdout. It doesn't convert uppercase letters to lowercase ones. I only "rewrote" jimianus's program.

    Say Lars needs only convert un uppercase document to lowercase. Then I think Lee's tr-command method is the easiest way to solve Lars's problem.

    More later.

    Bill
     
  16. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #16
    Lars here's an alternative way you can do this:

    Code:
    #include <stdio.h>
    #include <ctype.h>
    
    int main(int argc, const char *argv[])
    {
        char c;
    
        while( scanf("%c", &c) != EOF ) {
            if( isalpha(c) )
                c ^= 0x20;
            printf("%c", c);
        }
    
        return 0;
    }
    
    Then test it on it self:

    cat upcase.c | ./upcase
     
  17. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #17
    Sorry Bill. I really should forbid myself from posting first thing the morning before coffee. The criticism was unnecessarily harsh. It's my button to deal with.

    I only gave Lars the framework with which to use fgets because he hadn't encountered that yet. I left the actually case conversion to him as an exercise, which he seemed to want to do.

    And sorry Lars for hijacking your thread.
     
  18. larswik thread starter macrumors 68000

    Joined:
    Sep 8, 2006
    #18
    haha... Bill I had a good laugh. Let me better explain. The upper case to lower case gave me a chance to brush up on C since I have been Pascaling for the last couple months.

    Some one mailed me a script for a TV commercial I needed to shoot.

    The script I got.
    I decided to write a bit of code to do this. I could not find a way to copy the above script into a scanf or anything else, so I turned to the forum for help. After getting frustrated trying different methods I decided to just paste the script into the code before I compile it. Here is the code that worked at the end.

    Code:
    #include <stdio.h>
    #include <string.h>
    
    int main (int argc, const char * argv[]) {
    
    	int i, convertToInt, caseAdjustment;
    	
    	char upperCase[600];
    	char lowerCasePrint[600];
    	
    	char stringToCopy[] = "PASTE THE CODE HERE. PLEASE";
    	
    	strcpy(upperCase, stringToCopy);
    	
    	caseAdjustment = 32;
    	
    	lowerCasePrint[i] = upperCase[i];
    	
    //*** Loop start	
    	for (i = 1; i < 600; i++) { 
    		
    		convertToInt = (int)upperCase[i];
    		
    		if (convertToInt > 64 && convertToInt < 91 ) {
    			convertToInt += caseAdjustment; // finds lower case letter
    			lowerCasePrint[i] = (char)convertToInt;
    		}
    		
    		if (convertToInt == 46 || convertToInt == 33) {
    			(lowerCasePrint[i] = (char)convertToInt);
    			i++;
    			convertToInt = (int)upperCase[i];
    			{
    
    			if (convertToInt == 32) 
    				(lowerCasePrint[i] = (char)convertToInt);
    				i++;
    				lowerCasePrint[i] = upperCase[i];
    			}
    			
    		}
    		
    		else {
    			(lowerCasePrint[i] = (char)convertToInt);
    		}
    	}
    // *** Loop end	
    	
    	printf("The letter is: %s", lowerCasePrint);
    	
        return 0;
    }
    
    I am sure writing this code I took the scenic route and it is more wordy'er then it should be but it was kind of easy when I got in the rhythm of writing.

    I would still love to know if I can write it in a way that I can run the program and paste the text, hit return, and have it work. But I am sure this low level C language could never handle that :)

    Thanks!

    -Lars
     
  19. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #19

    Both fgets and scanf will let you paste in the text and hit return. If you referring to pasting the text before you start the program as arguments use argv.
     
  20. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #20
    FWIW.

    The "unix way" to handle this is, as the tr example and subsonix' code, as a filter between stdin and stdout.

    You get the input from the text file to the program using cat and a pipe (|) or using "<" redirection and then output it to a file using ">" redirection.

    (BTW: I take it from your ad copy that Red Robin is no longer at that location?)

    B
     
  21. Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #21
    No worries, jimianus. Your frank thoughts help me reevaluate my code. Although I hate C and C-like languages, I like to be able to write very concise code. Sometimes I even give in to the awful temptation to make a line of code do too much work. I got a reputation for writing "damn good code," a professor's phrase, not mine, in Pascal. I long to write elegant programs that anyone can understand. Unfortunately, C still temps me to try to be too clever. I need to stop letting concision impress me too much.
     
  22. Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #22
    Glad you got a laugh, Lars. I guess I don't know my own sense of humor. :) My funniest comments usually are serious.

    Scenic route or not, Lars, you still went where you wanted to go. With my penchant for missing the forest for the trees, I'd still be staring at a termite a woodpecker forgot to eat. ;)
     
  23. Bill McEnaney, Feb 28, 2011
    Last edited: Feb 28, 2011

    Bill McEnaney macrumors 6502

    Joined:
    Apr 29, 2010
    #23
    Code:
    while ((c = getchar()) != EOF)
    {
      if (isupper(c))
        c = tolower(c);
      putchar(c);
    }
    Code:
    while ((c = getchar()) != EOF)
      putchar(tolower(c));
    Do these code fragments no what Lars wants to do? The second fragment saves time because there's no if-statement in it. If tolower's argument isn't an uppercase letter, that function will just return that argument.
     
  24. subsonix macrumors 68040

    Joined:
    Feb 2, 2008
    #24
    Absolutely, but the if statement doesn't make any real difference at all.
     
  25. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #25
    Lars actually implemented sentence case. The first character after full-stop or exclamation mark and followed by a space is left in uppercase.
     

Share This Page