1
import qualified Data.ByteString.Lazy.Char8 as BS

stuff <- BS.readFile "stuff.txt"

How do take a specific character from a bytestring then change its ASCII and then put it back? Do I use readInt or something?

Ex: "aaaaa" ,"a" is 97 so minus 1 and you have "aa`aa"

hammar
  • 138,522
  • 17
  • 304
  • 385
ArchHaskeller
  • 1,270
  • 1
  • 12
  • 28
  • 3
    You should look at `Data.Text` for unicode support. I would replace any instance of `Data.ByteString.Lazy.Char8` with `Data.Text.Lazy` and use `Text` support. `Data.ByteString` should be used for binary. – alternative Aug 16 '11 at 19:29
  • 1
    Please ask a new question instead of changing your question into a completely different one. I've reverted the edit as it made the existing answers here irrelevant and confusing. – hammar Aug 16 '11 at 20:09

3 Answers3

2

How about BS.map pred? You can also use fromEnum and toEnum to make convert to / from Ints.

fuz
  • 88,405
  • 25
  • 200
  • 352
2

Others have addressed the problem of doing the byte operations, so I will focus on the other half of your question: selecting and updating a particular byte within a ByteString. Let's start with implementing the operation for plain lists, using a more familiar interface:

onNth :: Int -> (a -> a) -> ([a] -> [a])
onNth n f xs = case splitAt n xs of
    (beginning, x:ending) -> beginning ++ f x : ending
    _ -> xs -- happens when n is out-of-bounds

You might equivalently implement this using take and drop instead of splitAt. Now, how can we translate this to work on ByteStrings? Well, the ByteString interface offers take, drop, splitAt, append, and cons; the only thing we haven't quite got available is the pattern matching that we did in the x:ending part above. Luckily, ByteString does offer something similar:

uncons :: ByteString -> Maybe (Word8, ByteString)

So, using that, we can write a new onNth function that works for ByteStrings:

second :: (b -> c) -> (a, b) -> (a, c)
second f (a, b) = (a, f b)

onNth :: Int -> (Word8 -> Word8) -> (ByteString -> ByteString)
onNth n f bs = case second uncons (splitAt n bs) of
    (beginning, Just (x, ending)) -> append beginning (cons (f x) ending)
    _ -> bs -- again, for out-of-bounds cases

Finally, we can discuss what function we should use as the f :: Word8 -> Word8 argument above. Although you talk about text above, I will point out that you shouldn't be using ByteString for text anyway (ByteStrings are sequences of bytes, not sequences of Chars). Therefore, if you have chosen to use ByteString, you must be talking about bytes, not text. ;-)

Therefore, you really meant to ask about a function which decreases a byte by one, presumably wrapping around on a boundary. subtract 1 is a function that does exactly that, so to convert pack [97, 97, 97, 97, 97] to pack [97, 97, 96, 97, 97], you might write onNth 2 (subtract 1). Reads almost like English!

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
1

Once you've converted the bytes to Chars with BS.unpack, you can use fromEnum :: Char -> Int (or, equivalently, ord from Data.Char) to convert a Char to its ASCII value, which you can then manipulate like a normal integer. To convert an ASCII value from an Int back to a Char, use toEnum or Data.Char.chr, and the Chars can then be converted back to a ByteString with BS.pack or similar.

jwodder
  • 54,758
  • 12
  • 108
  • 124