> Thanks for the tip on print(String(validatingUTF8: buf)), that does > reproduce my input text, line for line, EXCEPT for wrapping every line in > "Optional(line-of-text-with-terminator)", for example "Optional("import > Glibc\n")". > > So, how does wrapping a line of UTF8 text in another character string > "Optional()" help me print the text? Is Optional() some kind of function? > If so, how is it intended to be used?
The inclusion of "Optional(…)" in the printout is meant to tell you that what you got wasn't a plain `String`, but an `Optional<String>`. `Optional` is a type Swift uses to express that a certain value might be `nil`. Essentially, an `Optional<String>` either contains a `String`, or it doesn't contain a `String`, in which case it is `nil`. To print the `Optional<String>`, you must first extract the `String` from it in some way, which is called "unwrapping" it. (Note: Although I've written the type `Optional<String>` out longhand, Swift has a very commonly used shorthand form: `String?`. This is what you'll see in most API listings.) In this case, the `String(validatingUTF8:)` constructor returns an `Optional<String>` instead of just a `String` because, if the bytes you pass it are not valid UTF-8, it returns `nil` instead of returning an invalid string. If you want to use the `String`, you need to decide how to unwrap it, and thus how to handle the `nil` case where the UTF-8 you passed in was invalid. Getting down to concrete code changes, what you need to do here is first separate the conversion to a `String` from the `print()` line: while fgets(&buf, Int32(BUFSIZE), file_handle) != nil { let possibleString = String(validatingUTF8: buf) print(possibleString) } And then use one of Swift's features for unwrapping Optional types. There are three simple ways you can choose from: 1. You can use the postfix `!` operator to extract the value from `possibleString`, failing an assertion (i.e. crashing) if `possibleString` happens to be `nil`. That sounds a little bit ridiculous, but if you have complete control of the input data and you know it should *never* contain invalid UTF-8, crashing is probably better than adding a code path to your program that you haven't really thought about because it "can't happen". while fgets(&buf, Int32(BUFSIZE), file_handle) != nil { let possibleString = String(validatingUTF8: buf) print(possibleString!) } 2. You can use the infix `??` operator to substitute a default value for the string. For instance, you might decide to print "[invalid]" for invalid text: while fgets(&buf, Int32(BUFSIZE), file_handle) != nil { let possibleString = String(validatingUTF8: buf) print(possibleString ?? "[invalid]") } 3. You can use the `if let` construct to test for whether `possibleString` has a value and, if so, use it. For instance, if you just want to skip invalid lines: while fgets(&buf, Int32(BUFSIZE), file_handle) != nil { let possibleString = String(validatingUTF8: buf) if let string = possibleString { print(string) } } Or if you wanted to print a message to `stderr` and exit with a nonzero return code: while fgets(&buf, Int32(BUFSIZE), file_handle) != nil { let possibleString = String(validatingUTF8: buf) if let string = possibleString { print(string) } else { fprintf(stderr, "Invalid UTF-8 byte sequence") exit(1) } } This second behavior, incidentally, might be better written as a `guard let` statement. `guard` is sort of the reverse of `if`—it has only an `else` block. The `else` block is also *required* to exit the scope it's in, for instance by calling `exit`, using `return`, failing an assertion, or (since we're in a loop) using `continue` or `break`. while fgets(&buf, Int32(BUFSIZE), file_handle) != nil { let possibleString = String(validatingUTF8: buf) guard let string = possibleString else { fprintf(stderr, "Invalid UTF-8 byte sequence") exit(1) } print(string) } You can see how the `guard` statement lets you leave the "happy path" unindented, whereas the equivalent `if` forced you to indent it. If you had several different conditions—the line must be valid, the line must not be empty, the line must contain only digits, etc.—then using `guard` for each of these conditions might make your code significantly more readable than it would be as a series of nested `if`s. -- Brent Royal-Gordon Architechies _______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users