[med-svn] [r-cran-stringr] 01/09: New upstream version 1.1.0

Andreas Tille tille at debian.org
Sat Nov 12 07:47:20 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-stringr.

commit 5921daf6e664931001879c813853fc2b2218df4b
Author: Andreas Tille <tille at debian.org>
Date:   Sat Nov 12 00:26:21 2016 +0100

    New upstream version 1.1.0
---
 DESCRIPTION                       |  12 +-
 MD5                               | 129 ++++++++++++----------
 NAMESPACE                         |   6 +-
 NEWS.md                           | 154 ++++++++++++++++++++++++++
 R/c.r                             |  12 +-
 R/count.r                         |  15 +--
 R/data.R                          |  29 +++++
 R/detect.r                        |  11 +-
 R/extract.r                       |  33 +++---
 R/interp.R                        | 224 ++++++++++++++++++++++++++++++++++++++
 R/locate.r                        |  32 ++----
 R/match.r                         |  21 ++--
 R/modifiers.r                     |  44 ++++++--
 R/pad-trim.r                      |  39 ++++++-
 R/replace.r                       |  64 ++++++++---
 R/split.r                         |  32 ++----
 R/stringr.R                       |   5 -
 R/subset.R                        |  10 +-
 R/view.R                          |  89 +++++++++++++++
 R/word.r                          |   4 +
 README.md                         |   5 +-
 build/vignette.rds                | Bin 211 -> 210 bytes
 data/fruit.rda                    | Bin 0 -> 540 bytes
 data/sentences.rda                | Bin 0 -> 11375 bytes
 data/words.rda                    | Bin 0 -> 3402 bytes
 inst/doc/stringr.Rmd              |   4 +-
 inst/doc/stringr.html             |  98 ++++++++++-------
 inst/htmlwidgets/lib/str_view.css |  11 ++
 inst/htmlwidgets/str_view.js      |  17 +++
 inst/htmlwidgets/str_view.yaml    |   5 +
 man/case.Rd                       |   2 +-
 man/invert_match.Rd               |   2 +-
 man/modifier-deprecated.Rd        |   4 +-
 man/modifiers.Rd                  |   9 +-
 man/pipe.Rd                       |   2 +-
 man/str_c.Rd                      |  14 ++-
 man/str_conv.Rd                   |   2 +-
 man/str_count.Rd                  |   2 +-
 man/str_detect.Rd                 |   2 +-
 man/str_dup.Rd                    |   2 +-
 man/str_extract.Rd                |  10 +-
 man/str_interp.Rd                 |  62 +++++++++++
 man/str_length.Rd                 |   2 +-
 man/str_locate.Rd                 |   2 +-
 man/str_match.Rd                  |   9 +-
 man/str_order.Rd                  |   2 +-
 man/str_pad.Rd                    |   5 +-
 man/str_replace.Rd                |   4 +-
 man/str_replace_na.Rd             |   4 +-
 man/str_split.Rd                  |   8 +-
 man/str_sub.Rd                    |   4 +-
 man/str_subset.Rd                 |   2 +-
 man/str_trim.Rd                   |   2 +-
 man/str_trunc.Rd                  |  33 ++++++
 man/str_view.Rd                   |  52 +++++++++
 man/str_wrap.Rd                   |   2 +-
 man/stringr-data.Rd               |  36 ++++++
 man/stringr.Rd                    |   9 --
 man/word.Rd                       |   2 +-
 tests/testthat/test-detect.r      |  20 ++--
 tests/testthat/test-dup.r         |  12 +-
 tests/testthat/test-extract.r     |  10 +-
 tests/testthat/test-interp.r      |  66 +++++++++++
 tests/testthat/test-join.r        |   6 +-
 tests/testthat/test-length.r      |  18 +--
 tests/testthat/test-locate.r      |  30 +++--
 tests/testthat/test-match.r       |  26 ++---
 tests/testthat/test-pad.r         |  10 +-
 tests/testthat/test-replace.r     |  57 ++++++++++
 tests/testthat/test-split.r       |  75 +++++++------
 tests/testthat/test-sub.r         |  48 ++++----
 tests/testthat/test-subset.r      |  10 ++
 tests/testthat/test-trim.r        |  18 ++-
 tests/testthat/test-word.r        |  12 ++
 tests/testthat/test-wrap.r        |   7 ++
 vignettes/stringr.Rmd             |   4 +-
 76 files changed, 1416 insertions(+), 409 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
index 4466789..a6f51dd 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,5 +1,5 @@
 Package: stringr
-Version: 1.0.0
+Version: 1.1.0
 Title: Simple, Consistent Wrappers for Common String Operations
 Description: A consistent, simple and easy to use set of wrappers around the
     fantastic 'stringi' package. All function and argument names (and positions)
@@ -13,12 +13,16 @@ Authors at R: c(
 License: GPL-2
 Depends: R (>= 2.14)
 Imports: stringi (>= 0.4.1), magrittr
-Suggests: testthat, knitr
+Suggests: testthat, knitr, htmltools, htmlwidgets, rmarkdown, covr
 VignetteBuilder: knitr
+URL: https://github.com/hadley/stringr
+BugReports: https://github.com/hadley/stringr/issues
+RoxygenNote: 5.0.1
+LazyData: true
 NeedsCompilation: no
-Packaged: 2015-04-29 12:46:34 UTC; hadley
+Packaged: 2016-08-19 14:42:23 UTC; hadley
 Author: Hadley Wickham [aut, cre, cph],
   RStudio [cph]
 Maintainer: Hadley Wickham <hadley at rstudio.com>
 Repository: CRAN
-Date/Publication: 2015-04-30 11:48:24
+Date/Publication: 2016-08-19 21:02:58
diff --git a/MD5 b/MD5
index aba939d..46f15b8 100644
--- a/MD5
+++ b/MD5
@@ -1,67 +1,84 @@
-f6c0f7228263e8d0c42f7b8581ee9da7 *DESCRIPTION
-54c1589e84ba5df2778a4e893ef72457 *NAMESPACE
-87ddd6605b202ee5d3ee22926e447100 *R/c.r
+660e33eaeb0b2d065987c16301ceddf4 *DESCRIPTION
+418f3881a82e6c06bc2fd35b75912326 *NAMESPACE
+6b7bb4664312869a77e785ec86054244 *NEWS.md
+602ca1848b4280919b889dcce1985932 *R/c.r
 9c5e91f93a404215e8c4946c5a3ac2b7 *R/case.R
 bc5a2a73f2842baf45454f53f324f274 *R/conv.R
-3ebde5c8b233eb438daa6eb6ef20b580 *R/count.r
-5a02f00b78b0090830f05b1747033e83 *R/detect.r
+9bcbcd4184483b252ce0ae00ae7cc80a *R/count.r
+425b4de1b9cfd96ec12ffa98352cf187 *R/data.R
+3243b04ceb3ef212f41996563c2b3868 *R/detect.r
 017248629447b588fd6e607c6a5b420e *R/dup.r
-033276694abb26130c10b31e087f71b9 *R/extract.r
+69c7bf3df301e410b60791b277ce3d67 *R/extract.r
+16c94e98a606be41be05f299437c2e9e *R/interp.R
 8ef6b7317657989078722686317f810b *R/length.r
-673284eb210305e4983f2618d55c2d7a *R/locate.r
-77cb46494e7208f2deb942ef897fdd52 *R/match.r
-f5d93cebd0efc3ad2f1a479c86f4c041 *R/modifiers.r
-7c467f8789c92d5e437f9b39cbc419f9 *R/pad-trim.r
-373404758535e696141d86d2cd4a1f9b *R/replace.r
+44a0e610f88dfe850562cb3f579d7f8c *R/locate.r
+733d4de0d77693b47fe2b24b1ca117dc *R/match.r
+4bd875dbb7d64543cfdb7a2008d3f0a2 *R/modifiers.r
+423e3766d98b030f26aef7496986b86a *R/pad-trim.r
+3e83d8d1a990c3104b365e7eaec124d1 *R/replace.r
 932f28001598d05ca5f977721e9bb131 *R/sort.R
-0b6092c4c346f20b2181c505e7d86912 *R/split.r
-994867fa3894453fc4d4832171eafee3 *R/stringr.R
+19f7b487c142462e73542a1045a95e82 *R/split.r
 657a92dfd6074f24e81c49279bd54297 *R/sub.r
-b925d9c285b6b377f1cb26205521ed29 *R/subset.R
+ef300583eb4793a4f0159f5c53e75565 *R/subset.R
 f583f5b5856f7cb5f2c5fbb04f39f8a8 *R/utils.R
-e289fd194fc7928e7159cf8afe1d0677 *R/word.r
+e2abdcd205330bc1aa537fed20a8760a *R/view.R
+a28d1e2666b667c3800983b1e1b8f6e8 *R/word.r
 200bb24c414024721759d59d2907eadd *R/wrap.r
-b838ad43bd80f67c1348cdfd1db69208 *README.md
-b536c8a62aa1b18eea448bf780b6f225 *build/vignette.rds
+e8b5b22a21cdea65d5119fba8ecabc15 *README.md
+849843ab5b82d66bfdac5b4f3343d405 *build/vignette.rds
+89f0d280160eb4419b23251639a728c2 *data/fruit.rda
+7ad07be2e18f2b3459b55adc0c03c498 *data/sentences.rda
+c99f00d311e24c76bbeabfc8a58b4b50 *data/words.rda
 8ffc45088b1068264eba4514b264d53a *inst/doc/stringr.R
-2d2afda9742a6d5ef5fa1c51a781bda9 *inst/doc/stringr.Rmd
-293072752c163cf1501f8948dd27cb2e *inst/doc/stringr.html
-7f5ecca60bf966d675cad61a9f96d5cd *man/case.Rd
-f2bce59645a8e34f5ce03d3c96b00481 *man/invert_match.Rd
-895425e477b9733374018900728a2900 *man/modifier-deprecated.Rd
-11c58e978d8a8b356967e4b2c0e74a1e *man/modifiers.Rd
-46b011f56b10d41a81084a43102f615b *man/pipe.Rd
-870530c70a8db2f1cd85638257365eae *man/str_c.Rd
-ead10b491a30fc630e7b12ea45a3bd13 *man/str_conv.Rd
-d99b1cc60142d76eefdc5b301e746de8 *man/str_count.Rd
-8277de388e437d825f74f5e14f114bb1 *man/str_detect.Rd
-20dccc633025393e296a7f8e0973bfb9 *man/str_dup.Rd
-7cd0c123e5673f99e4162b93a80f1674 *man/str_extract.Rd
-5cd37c9c64d70595c1ed8ce551f82789 *man/str_length.Rd
-81fac342bc1e6fe503d02c9673dce784 *man/str_locate.Rd
-3fd2199b7ff06db88c9ba6cd4722d6cd *man/str_match.Rd
-92b4ac302da8c85b58e31652655df6ab *man/str_order.Rd
-176c05214e4313f394e7714e1d202376 *man/str_pad.Rd
-211b5f4ab56a0771b3239d32ab2cd613 *man/str_replace.Rd
-ccd6299c89a844ec3573455cb4b86825 *man/str_replace_na.Rd
-ef5fcb6a4e71c6316da2157046a92138 *man/str_split.Rd
-f81e06be94e067d0ee7e972d2744ea01 *man/str_sub.Rd
-353ba68fb55d9274cc38d498d80a947e *man/str_subset.Rd
-b040d44ded59aaf147050d56ada196da *man/str_trim.Rd
-9b2a1aea53b13a1fd0edc924f55c370a *man/str_wrap.Rd
-93af066d98be9af372aa91351be491c1 *man/stringr.Rd
-9f42a2d37fae6d2bc33ac8e1255c9d42 *man/word.Rd
+413e34561c01308503e6bc783c359011 *inst/doc/stringr.Rmd
+dc047c46fce1c7d904228f04f294cae7 *inst/doc/stringr.html
+0cce813b2f19d701b1f00d51d42902c1 *inst/htmlwidgets/lib/str_view.css
+e7c37a495d4ae965400eeb1000dee672 *inst/htmlwidgets/str_view.js
+1763429826b7f9745d2e590e4ca4c119 *inst/htmlwidgets/str_view.yaml
+a8cf2920d15e44ce35fdb434174fe86c *man/case.Rd
+6bd36c43504097d68c16f275f10cc870 *man/invert_match.Rd
+867ece9169d129df0198d7a088587c36 *man/modifier-deprecated.Rd
+ec6cb5312ac29edf3ebf1fbe80add745 *man/modifiers.Rd
+7f15d9fd60f36bb4743cfb0fafeea78e *man/pipe.Rd
+e2fca59f2742bfc3b3a6d13f0a381663 *man/str_c.Rd
+c1df5ae44a9c4d4e94526962f4b7f965 *man/str_conv.Rd
+32e0f85fcf94197bd2563f63b7e43b1a *man/str_count.Rd
+40bd26da1ace34057846c683997f5cc4 *man/str_detect.Rd
+652ee618a77d49f1dfcc1cd0de3e50f4 *man/str_dup.Rd
+fff77c9ac7ddda0c6534fb4f41c9cacc *man/str_extract.Rd
+177ab86b4c63f2c639e434e5c5ff9b5e *man/str_interp.Rd
+0ef5f5a05809492af06b6d8f619a28fc *man/str_length.Rd
+d25faba0376340f4fe0627bc0ce2dc5f *man/str_locate.Rd
+c49cf17e667f9e24a6b07510b324f461 *man/str_match.Rd
+ce37ca980b4fcbc539705c717a020bfa *man/str_order.Rd
+0247696a8fcf533b84374ee688091c47 *man/str_pad.Rd
+9f15367dbd187a6503b81aad6b7fb73e *man/str_replace.Rd
+c7bce9f4d5ba40cbeab1c673ca637d3f *man/str_replace_na.Rd
+27f4e80bc8db2ceb3ed2cbfe02bef5a2 *man/str_split.Rd
+ff6271866c0d0d187459f2215d876c60 *man/str_sub.Rd
+5b032797228eb70a9ad2f517b833f6fb *man/str_subset.Rd
+6dcb096c7fd141773de59aba3a979e5b *man/str_trim.Rd
+054a22ebda3d0eaed1e5696ecd3253fc *man/str_trunc.Rd
+bf5d56ed8975ba6f36daa4df746be9f6 *man/str_view.Rd
+3a31054aa873254306a4b109f33da177 *man/str_wrap.Rd
+9ccdac653cd80024e514feb7ebe510dc *man/stringr-data.Rd
+c915980d93d7cdf412b19e80e85dd554 *man/word.Rd
 4ee9d05bd4688270eca8d85299cedcd1 *tests/testthat.R
 61f9d77768cf9ff813d382f9337178fb *tests/testthat/test-count.r
-c69fd2a84d10850f39b85819d60a32fb *tests/testthat/test-detect.r
-065f752787f210c753d5bb5feea7f7a5 *tests/testthat/test-dup.r
-a7623052beaad8b11fcdc1fbe1504599 *tests/testthat/test-extract.r
-0e49f9a28c45a65d7c6893f03a8c9ca0 *tests/testthat/test-join.r
-922366c3451f88871b9ce063529edb7a *tests/testthat/test-length.r
-76249df3c11c62fb11aef63899029790 *tests/testthat/test-locate.r
-3fbd8882c34a3923b7b12707af0a987d *tests/testthat/test-match.r
-3cfc28d6785f4a8c0796a7980c9aac90 *tests/testthat/test-pad.r
-f339473f66b14267ec4b86db14b97820 *tests/testthat/test-split.r
-c95563eafc4fad4c60504ae59225b9d0 *tests/testthat/test-sub.r
-7dc6b256c7c2d3af1483b84698494819 *tests/testthat/test-trim.r
-2d2afda9742a6d5ef5fa1c51a781bda9 *vignettes/stringr.Rmd
+0b1b63d62bb48585837b0b7031328dc4 *tests/testthat/test-detect.r
+2b336162dd9c107511565144566cf233 *tests/testthat/test-dup.r
+a246742977453883ed04e738dd16c975 *tests/testthat/test-extract.r
+84ee1da4470bbbd8eb8b5fd2f13526f7 *tests/testthat/test-interp.r
+6fe2c7933ec6c863e808320c60567a5f *tests/testthat/test-join.r
+6f525891e80befb684ff295d1b714f71 *tests/testthat/test-length.r
+b9c2324c1d46d0efdb1b5d448db09556 *tests/testthat/test-locate.r
+3e1efea0b4bd71682bb048d58ce5e7dd *tests/testthat/test-match.r
+9d4f02d9e2458e9ad849a218a3bd9f5c *tests/testthat/test-pad.r
+c15b2037c04e206c4cca61523dbda15a *tests/testthat/test-replace.r
+ed9fce46356a66a829054fd312dcec0d *tests/testthat/test-split.r
+e3a9e72abe44dec62d792922696d6d43 *tests/testthat/test-sub.r
+7e0381051472d2bf07693409413df193 *tests/testthat/test-subset.r
+286e2327b2be8839d9ef4cb95c31ef70 *tests/testthat/test-trim.r
+bf9e1f3e3b9adfb5157cf231126b8c47 *tests/testthat/test-word.r
+d64e6159b4a9792a22a0eded7d586dac *tests/testthat/test-wrap.r
+413e34561c01308503e6bc783c359011 *vignettes/stringr.Rmd
diff --git a/NAMESPACE b/NAMESPACE
index c70f329..78779ac 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,4 +1,4 @@
-# Generated by roxygen2 (4.1.0): do not edit by hand
+# Generated by roxygen2: do not edit by hand
 
 export("%>%")
 export("str_sub<-")
@@ -16,6 +16,7 @@ export(str_detect)
 export(str_dup)
 export(str_extract)
 export(str_extract_all)
+export(str_interp)
 export(str_join)
 export(str_length)
 export(str_locate)
@@ -36,6 +37,9 @@ export(str_to_lower)
 export(str_to_title)
 export(str_to_upper)
 export(str_trim)
+export(str_trunc)
+export(str_view)
+export(str_view_all)
 export(str_wrap)
 export(word)
 import(stringi)
diff --git a/NEWS.md b/NEWS.md
new file mode 100644
index 0000000..fa8c990
--- /dev/null
+++ b/NEWS.md
@@ -0,0 +1,154 @@
+# stringr 1.1.0
+
+* Add sample datasets: `fruit`, `words` and `sentences`.
+
+* `fixed()`, `regex()`, and `coll()` now throw an error if you use them with
+  anything other than a plain string (#60). I've clarified that the replacement
+  for `perl()` is `regex()` not `regexp()` (#61). `boundary()` has improved
+  defaults when splitting on non-word boundaries (#58, @lmullen).
+
+* `str_detect()` now can detect boundaries (by checking for a `str_count()` > 0)
+  (#120). `str_subset()` works similarly.
+  
+* `str_extract()` and `str_extract_all()` now work with `boundary()`. This is
+  particularly useful if you want to extract logical constructs like words
+  or sentences. `str_extract_all()` respects the `simplify` argument
+  when used with `fixed()` matches.
+
+* `str_subset()` now respects custom options for `fixed()` patterns 
+  (#79, @gagolews).
+  
+* `str_replace()` and `str_replace_all()` now behave correctly when a
+  replacement string contains `$`s, `\\\\1`, etc. (#83, #99).
+
+* `str_split()` gains a `simplify` argument to match `str_extract_all()` 
+  etc.
+  
+* `str_view()` and `str_view_all()` create HTML widgets that display regular 
+  expression matches (#96).
+  
+* `word()` returns `NA` for indexes greater than number of words (#112).
+
+# stringr 1.0.0
+
+* stringr is now powered by [stringi](https://github.com/Rexamine/stringi) 
+  instead of base R regular expressions. This improves unicode and support, and 
+  makes most operations considerably faster.  If you find stringr inadequate for
+  your string processing needs, I highly recommend looking at stringi in more
+  detail.
+
+* stringr gains a vignette, currently a straight forward update of the article
+  that appeared in the R Journal.
+
+* `str_c()` now returns a zero length vector if any of its inputs are 
+  zero length vectors. This is consistent with all other functions, and
+  standard R recycling rules. Similarly, using `str_c("x", NA)` now
+  yields `NA`. If you want `"xNA"`, use `str_replace_na()` on the inputs.
+
+* `str_replace_all()` gains a convenient syntax for applying multiple pairs of
+  pattern and replacement to the same vector:
+  
+    ```R
+    input <- c("abc", "def")
+    str_replace_all(input, c("[ad]" = "!", "[cf]" = "?"))
+    ```
+
+* `str_match()` now returns NA if an optional group doesn't match 
+  (previously it returned ""). This is more consistent with `str_extract()`
+  and other match failures.
+
+* New `str_subset()` keeps values that match a pattern. It's a convenient
+  wrapper for `x[str_detect(x)]` (#21, @jiho).
+
+* New `str_order()` and `str_sort()` allow you to sort and order strings
+  in a specified locale.
+
+* New `str_conv()` to convert strings from specified encoding to UTF-8.
+
+* New modifier `boundary()` allows you to count, locate and split by
+  character, word, line and sentence boundaries.
+
+* The documentation got a lot of love, and very similar functions (e.g.
+  first and all variants) are now documented together. This should hopefully
+  make it easier to locate the function you need.
+
+* `ignore.case(x)` has been deprecated in favour of 
+  `fixed|regex|coll(x, ignore.case = TRUE)`, `perl(x)` has been deprecated in 
+  favour of `regex(x)`.
+
+* `str_join()` is deprecated, please use `str_c()` instead.
+
+# stringr 0.6.2
+
+* fixed path in `str_wrap` example so works for more R installations.
+
+* remove dependency on plyr
+
+# stringr 0.6.1
+
+* Zero input to `str_split_fixed` returns 0 row matrix with `n` columns
+
+* Export `str_join`
+
+# stringr 0.6
+
+* new modifier `perl` that switches to Perl regular expressions
+
+* `str_match` now uses new base function `regmatches` to extract matches -
+  this should hopefully be faster than my previous pure R algorithm
+
+# stringr 0.5
+
+* new `str_wrap` function which gives `strwrap` output in a more convenient
+  format
+
+* new `word` function extract words from a string given user defined
+  separator (thanks to suggestion by David Cooper)
+
+* `str_locate` now returns consistent type when matching empty string (thanks
+  to Stavros Macrakis)
+
+* new `str_count` counts number of matches in a string.
+
+* `str_pad` and `str_trim` receive performance tweaks - for large vectors this
+  should give at least a two order of magnitude speed up
+
+* str_length returns NA for invalid multibyte strings
+
+* fix small bug in internal `recyclable` function
+
+# stringr 0.4
+
+ * all functions now vectorised with respect to string, pattern (and
+   where appropriate) replacement parameters
+ * fixed() function now tells stringr functions to use fixed matching, rather
+   than escaping the regular expression.  Should improve performance for
+   large vectors.
+ * new ignore.case() modifier tells stringr functions to ignore case of
+   pattern.
+ * str_replace renamed to str_replace_all and new str_replace function added.
+   This makes str_replace consistent with all functions.
+ * new str_sub<- function (analogous to substring<-) for substring replacement
+ * str_sub now understands negative positions as a position from the end of
+   the string. -1 replaces Inf as indicator for string end.
+ * str_pad side argument can be left, right, or both (instead of center)
+ * str_trim gains side argument to better match str_pad
+ * stringr now has a namespace and imports plyr (rather than requiring it)
+
+# stringr 0.3
+
+ * fixed() now also escapes |
+ * str_join() renamed to str_c()
+ * all functions more carefully check input and return informative error
+   messages if not as expected.
+ * add invert_match() function to convert a matrix of location of matches to
+   locations of non-matches
+ * add fixed() function to allow matching of fixed strings.
+
+# stringr 0.2
+
+ * str_length now returns correct results when used with factors
+ * str_sub now correctly replaces Inf in end argument with length of string
+ * new function str_split_fixed returns fixed number of splits in a character
+   matrix
+ * str_split no longer uses strsplit to preserve trailing breaks
diff --git a/R/c.r b/R/c.r
index 7df5993..3cf01ab 100644
--- a/R/c.r
+++ b/R/c.r
@@ -9,7 +9,13 @@
 #' the entire matrix collapsed to a single string.
 #'
 #' @param ... One or more character vectors. Zero length arguments
-#'   are removed.
+#'   are removed. Short arguments are recycled to the length of the
+#'   longest.
+#'
+#'   Like most other R functions, missing values are "infectious": whenever
+#'   a missing value is combined with another string the result will always
+#'   be missing. Use \code{\link{str_replace_na}} to convert \code{NA} to
+#'   \code{"NA"}
 #' @param sep String to insert between input vectors.
 #' @param collapse Optional string used to combine input vectors into single
 #'   string.
@@ -17,7 +23,7 @@
 #'   length equal to the longest input string. If \code{collapse} is
 #'   non-NULL, a character vector of length 1.
 #' @seealso \code{\link{paste}} for equivalent base R functionality, and
-#'    \code{\link[stringi]{stri_c}} which this function wraps
+#'    \code{\link[stringi]{stri_join}} which this function wraps
 #' @export str_c
 #' @examples
 #' str_c("Letter: ", letters)
@@ -32,12 +38,14 @@
 #' str_c(c("a", NA, "b"), "-d")
 #' # Use str_replace_NA to display literal NAs:
 #' str_c(str_replace_na(c("a", NA, "b")), "-d")
+#' @import stringi
 str_c <- function(..., sep = "", collapse = NULL) {
   stri_c(..., sep = sep, collapse = collapse, ignore_null = TRUE)
 }
 
 #' @export
 #' @rdname str_c
+#' @usage NULL
 str_join <- function(..., sep = "", collapse = NULL) {
   .Deprecated("str_c")
   stri_c(..., sep = sep, collapse = collapse, ignore_null = TRUE)
diff --git a/R/count.r b/R/count.r
index c43c752..12b43e6 100644
--- a/R/count.r
+++ b/R/count.r
@@ -22,15 +22,10 @@
 #' str_count(c("a.", "...", ".a.a"), fixed("."))
 str_count <- function(string, pattern = "") {
   switch(type(pattern),
-    empty = stri_count_boundaries(string,
-      opts_brkiter = stri_opts_brkiter(type = "character")),
-    bound = stri_count_boundaries(string,
-      opts_brkiter = attr(pattern, "options")),
-    fixed = stri_count_fixed(string, pattern,
-      opts_fixed = attr(pattern, "options")),
-    coll  = stri_count_coll(string, pattern,
-      opts_collator = attr(pattern, "options")),
-    regex = stri_count_regex(string, pattern,
-      opts_regex = attr(pattern, "options"))
+    empty = stri_count_boundaries(string, opts_brkiter = opts(pattern)),
+    bound = stri_count_boundaries(string, opts_brkiter = opts(pattern)),
+    fixed = stri_count_fixed(string, pattern, opts_fixed = opts(pattern)),
+    coll  = stri_count_coll(string, pattern, opts_collator = opts(pattern)),
+    regex = stri_count_regex(string, pattern, opts_regex = opts(pattern))
   )
 }
diff --git a/R/data.R b/R/data.R
new file mode 100644
index 0000000..b55e448
--- /dev/null
+++ b/R/data.R
@@ -0,0 +1,29 @@
+#' Sample character vectors for practicing string manipulations.
+#'
+#' \code{fruit} and \code{word} come from the \code{rcorpora} package
+#' written by Gabor Csardi; the data was collected by Darius Kazemi
+#' and made available at \url{https://github.com/dariusk/corpora}.
+#' \code{sentences} is a collection of "Harvard sentences" used for
+#' standardised testing of voice.
+#'
+#' @format A character vector.
+#' @name stringr-data
+#' @examples
+#' length(sentences)
+#' sentences[1:5]
+#'
+#' length(fruit)
+#' fruit[1:5]
+#'
+#' length(words)
+#' words[1:5]
+NULL
+
+#' @rdname stringr-data
+"sentences"
+
+#' @rdname stringr-data
+"fruit"
+
+#' @rdname stringr-data
+"words"
diff --git a/R/detect.r b/R/detect.r
index 0d07fa4..4047bf2 100644
--- a/R/detect.r
+++ b/R/detect.r
@@ -34,13 +34,10 @@
 str_detect <- function(string, pattern) {
   switch(type(pattern),
     empty = ,
-    bound = stop("Not implemented", call. = FALSE),
-    fixed = stri_detect_fixed(string, pattern,
-      opts_fixed = attr(pattern, "options")),
-    coll  = stri_detect_coll(string, pattern,
-      opts_collator = attr(pattern, "options")),
-    regex = stri_detect_regex(string, pattern,
-      opts_regex = attr(pattern, "options"))
+    bound = str_count(string, pattern) > 0,
+    fixed = stri_detect_fixed(string, pattern, opts_fixed = opts(pattern)),
+    coll  = stri_detect_coll(string,  pattern, opts_collator = opts(pattern)),
+    regex = stri_detect_regex(string, pattern, opts_regex = opts(pattern))
   )
 }
 
diff --git a/R/extract.r b/R/extract.r
index 254a642..ef9974e 100644
--- a/R/extract.r
+++ b/R/extract.r
@@ -4,9 +4,8 @@
 #'
 #' @inheritParams str_detect
 #' @return A character vector.
-#' @seealso \code{\link[stringi]{stri_extract_first}} and
-#'   \code{\link[stringi]{stri_extract_all}} for the underlying
-#'   implementation.
+#' @seealso \code{\link{str_match}} to extract matched groups;
+#'   \code{\link[stringi]{stri_extract}} for the underlying implementation.
 #' @param simplify If \code{FALSE}, the default, returns a list of character
 #'   vectors. If \code{TRUE} returns a character matrix.
 #' @export
@@ -25,16 +24,16 @@
 #' # Simplify results into character matrix
 #' str_extract_all(shopping_list, "\\b[a-z]+\\b", simplify = TRUE)
 #' str_extract_all(shopping_list, "\\d", simplify = TRUE)
+#'
+#' # Extract all words
+#' str_extract_all("This is, suprisingly, a sentence.", boundary("word"))
 str_extract <- function(string, pattern) {
   switch(type(pattern),
-    empty = ,
-    bound = stop("Not implemented", call. = FALSE),
-    fixed = stri_extract_first_fixed(string, pattern,
-      opts_fixed = attr(pattern, "options")),
-    coll  = stri_extract_first_coll(string, pattern,
-      opts_collator = attr(pattern, "options")),
-    regex = stri_extract_first_regex(string, pattern,
-      opts_regex = attr(pattern, "options"))
+    empty = stri_extract_first_boundaries(string, pattern, opts_brkiter = opts(pattern)),
+    bound = stri_extract_first_boundaries(string, pattern, opts_brkiter = opts(pattern)),
+    fixed = stri_extract_first_fixed(string, pattern, opts_fixed = opts(pattern)),
+    coll  = stri_extract_first_coll(string, pattern, opts_collator = opts(pattern)),
+    regex = stri_extract_first_regex(string, pattern, opts_regex = opts(pattern))
   )
 }
 
@@ -42,13 +41,15 @@ str_extract <- function(string, pattern) {
 #' @export
 str_extract_all <- function(string, pattern, simplify = FALSE) {
   switch(type(pattern),
-    empty = ,
-    bound = stop("Not implemented", call. = FALSE),
+    empty = stri_extract_all_boundaries(string, pattern,
+      simplify = simplify, omit_no_match = TRUE, opts_brkiter = opts(pattern)),
+    bound = stri_extract_all_boundaries(string, pattern,
+      simplify = simplify, omit_no_match = TRUE, opts_brkiter = opts(pattern)),
     fixed = stri_extract_all_fixed(string, pattern,
-      opts_fixed = attr(pattern, "options")),
+      simplify = simplify, omit_no_match = TRUE, opts_fixed = opts(pattern)),
     coll  = stri_extract_all_coll(string, pattern,
-      simplify = simplify, omit_no_match = TRUE, attr(pattern, "options")),
+      simplify = simplify, omit_no_match = TRUE, opts_collator = opts(pattern)),
     regex = stri_extract_all_regex(string, pattern,
-      simplify = simplify, omit_no_match = TRUE, attr(pattern, "options"))
+      simplify = simplify, omit_no_match = TRUE, opts_regex = opts(pattern))
   )
 }
diff --git a/R/interp.R b/R/interp.R
new file mode 100644
index 0000000..3554773
--- /dev/null
+++ b/R/interp.R
@@ -0,0 +1,224 @@
+#' String interpolation.
+#'
+#' String interpolation is a useful way of specifying a character string which
+#' depends on values in a certain environment. It allows for string creation
+#' which is easier to read and write when compared to using e.g.
+#' \code{\link{paste}} or \code{\link{sprintf}}. The (template) string can
+#' include expression placeholders of the form \code{${expression}} or
+#' \code{$[format]{expression}}, where expressions are valid R expressions that
+#' can be evaluated in the given environment, and \code{format} is a format
+#' specification valid for use with \code{\link{sprintf}}.
+#'
+#' @param string A template character string. This function is not vectorised:
+#'   a character vector will be collapsed into a single string.
+#' @param env The environment in which to evaluate the expressions.
+#' @return An interpolated character string.
+#' @author Stefan Milton Bache
+#' @export
+#' @examples
+#'
+#' # Using values from the environment, and some formats
+#' user_name <- "smbache"
+#' amount <- 6.656
+#' account <- 1337
+#' str_interp("User ${user_name} (account $[08d]{account}) has $$[.2f]{amount}.")
+#'
+#' # Nested brace pairs work inside expressions too, and any braces can be
+#' # placed outside the expressions.
+#' str_interp("Works with } nested { braces too: $[.2f]{{{2 + 2}*{amount}}}")
+#'
+#' # Values can also come from a list
+#' str_interp(
+#'   "One value, ${value1}, and then another, ${value2*2}.",
+#'   list(value1 = 10, value2 = 20)
+#' )
+#'
+#' # Or a data frame
+#' str_interp(
+#'   "Values are $[.2f]{max(Sepal.Width)} and $[.2f]{min(Sepal.Width)}.",
+#'   iris
+#' )
+#'
+#' # Use a vector when the string is long:
+#' max_char <- 80
+#' str_interp(c(
+#'   "This particular line is so long that it is hard to write ",
+#'   "without breaking the ${max_char}-char barrier!"
+#' ))
+str_interp <- function(string, env = parent.frame()) {
+  if (!is.character(string)) {
+    stop("string argument is not character.", call. = FALSE)
+  }
+  string <- str_c(string, collapse = "")
+
+  # Find expression placeholders
+  matches      <- interp_placeholders(string)
+
+  # Determine if any placeholders were found.
+  if (matches$indices[1] <= 0) {
+    string
+  } else {
+    # Evaluate them to get the replacement strings.
+    replacements <- eval_interp_matches(matches$matches, env)
+
+    # Replace the expressions by their values and return.
+    `regmatches<-`(string, list(matches$indices), FALSE, list(replacements))
+  }
+}
+
+#' Match String Interpolation Placeholders
+#'
+#' Given a character string a set of expression placeholders are matched. They
+#' are of the form \code{${...}} or optionally \code{$[f]{...}} where \code{f}
+#' is a valid format for \code{\link{sprintf}}.
+#'
+#' @param string character: The string to be interpolated.
+#'
+#' @return list containing \code{indices} (regex match data) and \code{matches},
+#'   the string representations of matched expressions.
+#'
+#' @noRd
+#' @author Stefan Milton Bache
+interp_placeholders <- function(string) {
+  # Find starting position of ${} or $[]{} placeholders.
+  starts   <- gregexpr("\\$(\\[.*?\\])?\\{", string)[[1]]
+
+  # Return immediately if no matches are found.
+  if (starts[1] <= 0)
+    return(list(indices = starts))
+
+  # Break up the string in parts
+  parts <- substr(rep(string, length(starts)),
+                  start = starts,
+                  stop  = c(starts[-1L] - 1L, nchar(string)))
+
+  # If there are nested placeholders, each part will not contain a full
+  # placeholder in which case we report invalid string interpolation template.
+  if (any(!grepl("\\$(\\[.*?\\])?\\{.+\\}", parts)))
+    stop("Invalid template string for interpolation.", call. = FALSE)
+
+  # For each part, find the opening and closing braces.
+  opens  <- lapply(strsplit(parts, ""), function(v) which(v == "{"))
+  closes <- lapply(strsplit(parts, ""), function(v) which(v == "}"))
+
+  # Identify the positions within the parts of the matching closing braces.
+  # These are the lengths of the placeholder matches.
+  lengths <- mapply(match_brace, opens, closes)
+
+  # Update the `starts` match data with the
+  attr(starts, "match.length") <- lengths
+
+  # Return both the indices (regex match data) and the actual placeholder
+  # matches (as strings.)
+  list(indices = starts,
+       matches = mapply(substr, starts, starts + lengths - 1, x = string))
+}
+
+#' Evaluate String Interpolation Matches
+#'
+#' The expression part of string interpolation matches are evaluated in a
+#' specified environment and formatted for replacement in the original string.
+#' Used internally by \code{\link{str_interp}}.
+#'
+#' @param matches Match data
+#'
+#' @param env The environment in which to evaluate the expressions.
+#'
+#' @return A character vector of replacement strings.
+#'
+#' @noRd
+#' @author Stefan Milton Bache
+eval_interp_matches <- function(matches, env) {
+  # Extract expressions from the matches
+  expressions <- extract_expressions(matches)
+
+  # Evaluate them in the given environment
+  values <- lapply(expressions, eval, env = env,
+                   enclos = if (is.environment(env)) env else environment(env))
+
+  # Find the formats to be used
+  formats <- extract_formats(matches)
+
+  # Format the values and return.
+  mapply(sprintf, formats, values)
+}
+
+#' Extract Expression Objects from String Interpolation Matches
+#'
+#' An interpolation match object will contain both its wrapping \code{${ }} part
+#' and possibly a format. This extracts the expression parts and parses them to
+#' prepare them for evaluation.
+#'
+#' @param matches Match data
+#'
+#' @return list of R expressions
+#'
+#' @noRd
+#' @author Stefan Milton Bache
+extract_expressions <- function(matches) {
+  # Parse function for text argument as first argument.
+  parse_text <- function(text) {
+    tryCatch(
+      parse(text = text),
+      error = function(e) stop(conditionMessage(e), call. = FALSE)
+    )
+  }
+
+  # string representation of the expressions (without the possible formats).
+  strings  <- gsub("\\$(\\[.+?\\])?\\{", "", matches)
+
+  # Remove the trailing closing brace and parse.
+  lapply(substr(strings, 1L, nchar(strings) - 1), parse_text)
+}
+
+
+#' Extract String Interpolation Formats from Matched Placeholders
+#'
+#' An expression placeholder for string interpolation may optionally contain a
+#' format valid for \code{\link{sprintf}}. This function will extract such or
+#' default to "s" the format for strings.
+#'
+#' @param matches Match data
+#'
+#' @return A character vector of format specifiers.
+#'
+#' @noRd
+#' @author Stefan Milton Bache
+extract_formats <- function(matches) {
+  # Extract the optional format parts.
+  formats <- gsub("\\$(\\[(.+?)\\])?.*", "\\2", matches)
+
+  # Use string options "s" as default when not specified.
+  paste0("%", ifelse(formats == "", "s", formats))
+}
+
+#' Utility Function for Matching a Closing Brace
+#'
+#' Given positions of opening and closing braces \code{match_brace} identifies
+#' the closing brace matching the first opening brace.
+#'
+#' @param opening integer: Vector with positions of opening braces.
+#'
+#' @param closing integer: Vector with positions of closing braces.
+#'
+#' @return Integer with the posision of the matching brace.
+#'
+#' @noRd
+#' @author Stefan Milton Bache
+match_brace <- function(opening, closing) {
+  # maximum index for the matching closing brace
+  max_close <- max(closing)
+
+  # "path" for mapping opening and closing breaces
+  path <- numeric(max_close)
+
+  # Set openings to 1, and closings to -1
+  path[opening[opening < max_close]] <-  1
+  path[closing] <- -1
+
+  # Cumulate the path ...
+  cumpath <- cumsum(path)
+
+  # ... and the first 0 after the first opening identifies the match.
+  min(which(1:max_close > min(which(cumpath == 1)) & cumpath == 0))
+}
diff --git a/R/locate.r b/R/locate.r
index b2cf54b..1db1a7b 100644
--- a/R/locate.r
+++ b/R/locate.r
@@ -27,33 +27,25 @@
 #' str_locate_all(fruit, "")
 str_locate <- function(string, pattern) {
   switch(type(pattern),
-    empty = stri_locate_first_boundaries(string,
-      opts_brkiter = stri_opts_brkiter("character")),
-    bound = stri_locate_first_boundaries(string,
-      opts_brkiter = attr(pattern, "options")),
-    fixed = stri_locate_first_fixed(string, pattern,
-      opts_fixed = attr(pattern, "options")),
-    coll  = stri_locate_first_coll(string, pattern,
-      opts_collator = attr(pattern, "options")),
-    regex = stri_locate_first_regex(string, pattern,
-      opts_regex = attr(pattern, "options"))
+    empty = stri_locate_first_boundaries(string, opts_brkiter = opts(pattern)),
+    bound = stri_locate_first_boundaries(string, opts_brkiter = opts(pattern)),
+    fixed = stri_locate_first_fixed(string, pattern, opts_fixed = opts(pattern)),
+    coll  = stri_locate_first_coll(string, pattern, opts_collator = opts(pattern)),
+    regex = stri_locate_first_regex(string, pattern, opts_regex = opts(pattern))
   )
 }
 
 #' @rdname str_locate
 #' @export
 str_locate_all <- function(string, pattern) {
+  opts <- opts(pattern)
+
   switch(type(pattern),
-    empty = stri_locate_all_boundaries(string, omit_no_match = TRUE,
-      opts_brkiter = stri_opts_brkiter("character")),
-    bound = stri_locate_all_boundaries(string, omit_no_match = TRUE,
-      opts_brkiter = attr(pattern, "options")),
-    fixed = stri_locate_all_fixed(string, pattern, omit_no_match = TRUE,
-      opts_fixed = attr(pattern, "options")),
-    regex = stri_locate_all_regex(string, pattern,
-      omit_no_match = TRUE, opts_regex = attr(pattern, "options")),
-    coll  = stri_locate_all_coll(string, pattern,
-      omit_no_match = TRUE, opts_collator = attr(pattern, "options"))
+    empty = stri_locate_all_boundaries(string, omit_no_match = TRUE, opts_brkiter = opts),
+    bound = stri_locate_all_boundaries(string, omit_no_match = TRUE, opts_brkiter = opts),
+    fixed = stri_locate_all_fixed(string, pattern, omit_no_match = TRUE, opts_fixed = opts),
+    regex = stri_locate_all_regex(string, pattern, omit_no_match = TRUE, opts_regex = opts),
+    coll  = stri_locate_all_coll(string, pattern, omit_no_match = TRUE, opts_collator = opts)
   )
 }
 
diff --git a/R/match.r b/R/match.r
index 03846c7..df6bce8 100644
--- a/R/match.r
+++ b/R/match.r
@@ -34,21 +34,24 @@
 #' str_extract(x, "<.*?>")
 #' str_extract_all(x, "<.*?>")
 str_match <- function(string, pattern) {
-  switch(type(pattern),
-    regex = stri_match_first_regex(string, pattern,
-      opts_regex = attr(pattern, "options")),
+  if (type(pattern) != "regex") {
     stop("Can only match regular expressions", call. = FALSE)
-  )
+  }
+
+  stri_match_first_regex(string, pattern, opts_regex = opts(pattern))
 }
 
 #' @rdname str_match
 #' @export
 str_match_all <- function(string, pattern) {
-  switch(type(pattern),
-    regex = stri_match_all_regex(string, pattern,
-      cg_missing = "",
-      omit_no_match = TRUE,
-      opts_regex = attr(pattern, "options")),
+  if (type(pattern) != "regex") {
     stop("Can only match regular expressions", call. = FALSE)
+  }
+
+  stri_match_all_regex(string,
+    pattern,
+    cg_missing = "",
+    omit_no_match = TRUE,
+    opts_regex = opts(pattern)
   )
 }
diff --git a/R/modifiers.r b/R/modifiers.r
index 3fffe9d..4d327aa 100644
--- a/R/modifiers.r
+++ b/R/modifiers.r
@@ -4,7 +4,7 @@
 #'  \item{fixed}{Compare literal bytes in the string. This is very fast, but
 #'    not usually what you want for non-ASCII character sets.}
 #'  \item{coll}{Compare strings respecting standard collation rules.}
-#'  \item{regexp}{The default. Uses ICU regular expressions.}
+#'  \item{regex}{The default. Uses ICU regular expressions.}
 #'  \item{boundary}{Match boundaries between things.}
 #' }
 #'
@@ -45,6 +45,10 @@ NULL
 #' @export
 #' @rdname modifiers
 fixed <- function(pattern, ignore_case = FALSE) {
+  if (!is_bare_character(pattern)) {
+    stop("Can only modify plain character vectors.", call. = FALSE)
+  }
+
   options <- stri_opts_fixed(case_insensitive = ignore_case)
 
   structure(
@@ -63,6 +67,10 @@ fixed <- function(pattern, ignore_case = FALSE) {
 #'   \code{\link[stringi]{stri_opts_regex}}, or
 #'   \code{\link[stringi]{stri_opts_brkiter}}
 coll <- function(pattern, ignore_case = FALSE, locale = NULL, ...) {
+  if (!is_bare_character(pattern)) {
+    stop("Can only modify plain character vectors.", call. = FALSE)
+  }
+
   options <- stri_opts_collator(
     strength = if (ignore_case) 2L else 3L,
     locale = locale,
@@ -86,6 +94,10 @@ coll <- function(pattern, ignore_case = FALSE, locale = NULL, ...) {
 #' @param dotall If \code{TRUE}, \code{.} will also match line terminators.
 regex <- function(pattern, ignore_case = FALSE, multiline = FALSE,
                    comments = FALSE, dotall = FALSE, ...) {
+  if (!is_bare_character(pattern)) {
+    stop("Can only modify plain character vectors.", call. = FALSE)
+  }
+
   options <- stri_opts_regex(
     case_insensitive = ignore_case,
     multiline = multiline,
@@ -103,12 +115,18 @@ regex <- function(pattern, ignore_case = FALSE, multiline = FALSE,
 
 #' @param type Boundary type to detect.
 #' @param skip_word_none Ignore "words" that don't contain any characters
-#'   or numbers - i.e. punctuation.
+#'   or numbers - i.e. punctuation. Default \code{NA} will skip such "words"
+#'   only when splitting on \code{word} boundaries.
 #' @export
 #' @rdname modifiers
 boundary <- function(type = c("character", "line_break", "sentence", "word"),
-                    skip_word_none = TRUE, ...) {
+                    skip_word_none = NA, ...) {
   type <- match.arg(type)
+
+  if (identical(skip_word_none, NA)) {
+    skip_word_none <- type == "word"
+  }
+
   options <- stri_opts_brkiter(
     type = type,
     skip_word_none = skip_word_none,
@@ -122,16 +140,24 @@ boundary <- function(type = c("character", "line_break", "sentence", "word"),
   )
 }
 
+opts <- function(x) {
+  if (identical(x, "")) {
+    stri_opts_brkiter(type = "character")
+  } else {
+    attr(x, "options")
+  }
+}
+
 type <- function(x) UseMethod("type")
 type.boundary <- function(x) "bound"
-type.regexp <- function(x) "regex"
+type.regex <- function(x) "regex"
 type.coll <- function(x) "coll"
 type.fixed <- function(x) "fixed"
 type.character <- function(x) if (identical(x, "")) "empty" else "regex"
 
 #' Deprecated modifier functions.
 #'
-#' Please use \code{\link{regexp}} and \code{\link{coll}} instead.
+#' Please use \code{\link{regex}} and \code{\link{coll}} instead.
 #'
 #' @name modifier-deprecated
 #' @keywords internal
@@ -140,13 +166,17 @@ NULL
 #' @export
 #' @rdname modifier-deprecated
 ignore.case <- function(string) {
-  message("Please use (fixed|coll|regexp)(x, ignore_case = TRUE) instead of ignore.case(x)")
+  message("Please use (fixed|coll|regex)(x, ignore_case = TRUE) instead of ignore.case(x)")
   fixed(string, ignore_case = TRUE)
 }
 
 #' @export
 #' @rdname modifier-deprecated
 perl <- function(pattern) {
-  message("perl is deprecated. Please use regexp instead")
+  message("perl is deprecated. Please use regex() instead")
   regex(pattern)
 }
+
+is_bare_character <- function(x) {
+  is.character(x) && !is.object(x)
+}
diff --git a/R/pad-trim.r b/R/pad-trim.r
index 466e21f..b02d240 100644
--- a/R/pad-trim.r
+++ b/R/pad-trim.r
@@ -7,7 +7,8 @@
 #' @param side Side on which padding character is added (left, right or both).
 #' @param pad Single padding character (default is a space).
 #' @return A character vector.
-#' @seealso \code{\link{str_trim}} to remove whitespace
+#' @seealso \code{\link{str_trim}} to remove whitespace;
+#'   \code{\link{str_trunc}} to decrease the maximum width of a string.
 #' @export
 #' @examples
 #' rbind(
@@ -33,6 +34,42 @@ str_pad <- function(string, width, side = c("left", "right", "both"), pad = " ")
   )
 }
 
+#' Truncate a character string.
+#'
+#' @param string A character vector.
+#' @param width Maximum width of string.
+#' @param side,ellipsis Location and content of ellipsis that indicates
+#'   content has been removed.
+#' @seealso \code{\link{str_pad}} to increase the minimum width of a string.
+#' @export
+#' @examples
+#' x <- "This string is moderately long"
+#' rbind(
+#'   str_trunc(x, 20, "right"),
+#'   str_trunc(x, 20, "left"),
+#'   str_trunc(x, 20, "center")
+#' )
+#'
+str_trunc <- function(string, width, side = c("right", "left", "center"),
+                      ellipsis = "...") {
+  side <- match.arg(side)
+
+  too_long <- str_length(string) > width
+  width... <- width - str_length(ellipsis)
+
+  string[too_long] <- switch(side,
+    right  = str_c(str_sub(string[too_long], 1, width...), ellipsis),
+    left   = str_c(ellipsis, str_sub(string[too_long], -width..., -1)),
+    center = str_c(
+        str_sub(string[too_long], 1, ceiling(width... / 2)),
+        ellipsis,
+        str_sub(string[too_long], -floor(width... / 2), -1)
+      )
+  )
+  string
+}
+
+
 #' Trim whitespace from start and end of string.
 #'
 #' @param string A character vector.
diff --git a/R/replace.r b/R/replace.r
index fd3047c..2d8c107 100644
--- a/R/replace.r
+++ b/R/replace.r
@@ -39,17 +39,15 @@
 #' str_replace_all(str_c(fruits, collapse = "---"),
 #'  c("one" = 1, "two" = 2, "three" = 3))
 str_replace <- function(string, pattern, replacement) {
-  replacement <- fix_replacement(replacement)
-
   switch(type(pattern),
     empty = ,
     bound = stop("Not implemented", call. = FALSE),
     fixed = stri_replace_first_fixed(string, pattern, replacement,
-      opts_fixed = attr(pattern, "options")),
+      opts_fixed = opts(pattern)),
     coll  = stri_replace_first_coll(string, pattern, replacement,
-      opts_collator = attr(pattern, "options")),
-    regex = stri_replace_first_regex(string, pattern, replacement,
-      opts_regex = attr(pattern, "options")),
+      opts_collator = opts(pattern)),
+    regex = stri_replace_first_regex(string, pattern, fix_replacement(replacement),
+      opts_regex = opts(pattern))
   )
 }
 
@@ -57,29 +55,65 @@ str_replace <- function(string, pattern, replacement) {
 #' @rdname str_replace
 str_replace_all <- function(string, pattern, replacement) {
   if (!is.null(names(pattern))) {
+    vec <- FALSE
     replacement <- unname(pattern)
     pattern <- names(pattern)
-    vec <- FALSE
   } else {
     vec <- TRUE
   }
-  replacement <- fix_replacement(replacement)
 
   switch(type(pattern),
     empty = ,
     bound = stop("Not implemented", call. = FALSE),
     fixed = stri_replace_all_fixed(string, pattern, replacement,
-      vectorize_all = vec, opts_fixed = attr(pattern, "options")),
+      vectorize_all = vec, opts_fixed = opts(pattern)),
     coll  = stri_replace_all_coll(string, pattern, replacement,
-      vectorize_all = vec, opts_collator = attr(pattern, "options")),
-    regex = stri_replace_all_regex(string, pattern, replacement,
-      vectorize_all = vec, opts_regex = attr(pattern, "options"))
+      vectorize_all = vec, opts_collator = opts(pattern)),
+    regex = stri_replace_all_regex(string, pattern, fix_replacement(replacement),
+      vectorize_all = vec, opts_regex = opts(pattern))
   )
 }
 
 fix_replacement <- function(x) {
-  stri_replace_all_regex(x, c("\\$", "\\\\(\\d)"), c("\\\\$", "\\$$1"),
-    vectorize_all = FALSE)
+  vapply(x, fix_replacement_one, character(1), USE.NAMES = FALSE)
+}
+
+fix_replacement_one <- function(x) {
+  escape_dollar <- function(x) if (x == "$") "\\$" else x
+
+  chars <- str_split(x, "")[[1]]
+  out <- character(length(chars))
+  escaped <- logical(length(chars))
+
+  in_escape <- FALSE
+  for (i in seq_along(chars)) {
+    escaped[[i]] <- in_escape
+    char <- chars[[i]]
+
+    if (in_escape) {
+      # Escape character not printed previously so must include here
+      if (char == "$") {
+        out[[i]] <- "\\\\$"
+      } else if (char >= "0" && char <= "9") {
+        out[[i]] <- paste0("$", char)
+      } else {
+        out[[i]] <- paste0("\\", char)
+      }
+
+      in_escape <- FALSE
+    } else {
+      if (char == "$") {
+        out[[i]] <- "\\$"
+      } else if (char == "\\") {
+        in_escape <- TRUE
+      } else {
+        out[[i]] <- char
+      }
+    }
+  }
+
+  # tibble::tibble(chars, out, escaped)
+  paste0(out, collapse = "")
 }
 
 
@@ -88,7 +122,7 @@ fix_replacement <- function(x) {
 #' @inheritParams str_replace
 #' @export
 #' @examples
-#' str_replace_na(c("NA", "abc", "def"))
+#' str_replace_na(c(NA, "abc", "def"))
 str_replace_na <- function(string, replacement = "NA") {
   stri_replace_na(string, replacement)
 }
diff --git a/R/split.r b/R/split.r
index 900190b..c6e45a3 100644
--- a/R/split.r
+++ b/R/split.r
@@ -3,6 +3,7 @@
 #' Vectorised over \code{string} and \code{pattern}.
 #'
 #' @inheritParams str_detect
+#' @inheritParams str_extract
 #' @param n number of pieces to return.  Default (Inf) uses all
 #'   possible split positions.
 #'
@@ -19,6 +20,7 @@
 #' )
 #'
 #' str_split(fruits, " and ")
+#' str_split(fruits, " and ", simplify = TRUE)
 #'
 #' # Specify n to restrict the number of possible matches
 #' str_split(fruits, " and ", n = 3)
@@ -29,38 +31,22 @@
 #' # Use fixed to return a character matrix
 #' str_split_fixed(fruits, " and ", 3)
 #' str_split_fixed(fruits, " and ", 4)
-str_split <- function(string, pattern, n = Inf) {
+str_split <- function(string, pattern, n = Inf, simplify = FALSE) {
   if (identical(n, Inf)) n <- -1L
 
   switch(type(pattern),
-    empty = stri_split_boundaries(string, n = n, simplify = FALSE,
-      opts_brkiter = stri_opts_brkiter(type = "character")),
-    bound = stri_split_boundaries(string, n = n, simplify = FALSE,
-      opts_brkiter = attr(pattern, "options")),
-    fixed = stri_split_fixed(string, pattern, n = n, simplify = FALSE,
-      opts_fixed = attr(pattern, "options")),
-    regex = stri_split_regex(string, pattern, n = n, simplify = FALSE,
-      opts_regex = attr(pattern, "options")),
-    coll  = stri_split_coll(string, pattern, n = n, simplify = FALSE,
-      opts_collator = attr(pattern, "options"))
+    empty = stri_split_boundaries(string, n = n, simplify = simplify, opts_brkiter = opts(pattern)),
+    bound = stri_split_boundaries(string, n = n, simplify = simplify, opts_brkiter = opts(pattern)),
+    fixed = stri_split_fixed(string, pattern, n = n, simplify = simplify, opts_fixed = opts(pattern)),
+    regex = stri_split_regex(string, pattern, n = n, simplify = simplify, opts_regex = opts(pattern)),
+    coll  = stri_split_coll(string, pattern, n = n, simplify = simplify, opts_collator = opts(pattern))
   )
 }
 
 #' @export
 #' @rdname str_split
 str_split_fixed <- function(string, pattern, n) {
-  out <- switch(type(pattern),
-    empty = stri_split_boundaries(string, n = n, simplify = TRUE,
-      opts_brkiter = stri_opts_brkiter(type = "character")),
-    bound = stri_split_boundaries(string, n = n, simplify = TRUE,
-      opts_brkiter = attr(pattern, "options")),
-    fixed = stri_split_fixed(string, pattern, n = n, simplify = TRUE,
-      opts_fixed = attr(pattern, "options")),
-    regex = stri_split_regex(string, pattern, n = n, simplify = TRUE,
-      opts_regex = attr(pattern, "options")),
-    coll  = stri_split_coll(string, pattern, n = n, simplify = TRUE,
-      opts_collator = attr(pattern, "options"))
-  )
+  out <- str_split(string, pattern, n = n, simplify = TRUE)
   out[is.na(out)] <- ""
   out
 }
diff --git a/R/stringr.R b/R/stringr.R
deleted file mode 100644
index f0bef11..0000000
--- a/R/stringr.R
+++ /dev/null
@@ -1,5 +0,0 @@
-#' Fast and friendly string manipulation.
-#'
-#' @name stringr
-#' @import stringi
-NULL
diff --git a/R/subset.R b/R/subset.R
index 6b3f5cf..7b7f36a 100644
--- a/R/subset.R
+++ b/R/subset.R
@@ -21,11 +21,9 @@
 str_subset <- function(string, pattern) {
   switch(type(pattern),
     empty = ,
-    bound = stop("Not implemented", call. = FALSE),
-    fixed = stri_subset_fixed(string, pattern, omit_na = TRUE),
-    coll  = stri_subset_coll(string, pattern, omit_na = TRUE,
-      opts_collator = attr(pattern, "options")),
-    regex = stri_subset_regex(string, pattern, omit_na = TRUE,
-      opts_regex = attr(pattern, "options"))
+    bound = string[str_detect(string, pattern)],
+    fixed = stri_subset_fixed(string, pattern, omit_na = TRUE, opts_fixed = opts(pattern)),
+    coll  = stri_subset_coll(string, pattern, omit_na = TRUE, opts_collator = opts(pattern)),
+    regex = stri_subset_regex(string, pattern, omit_na = TRUE, opts_regex = opts(pattern))
   )
 }
diff --git a/R/view.R b/R/view.R
new file mode 100644
index 0000000..36c3dd0
--- /dev/null
+++ b/R/view.R
@@ -0,0 +1,89 @@
+#' View HTML rendering of regular expression match.
+#'
+#' \code{str_view} shows the first match; \code{str_view_all} shows all
+#' the matches.
+#'
+#' @inheritParams str_detect
+#' @param match If \code{TRUE}, shows only strings that match the pattern.
+#'   If \code{FALSE}, shows only the strings that don't match the pattern.
+#'   Otherwise (the default, \code{NA}) displays both matches and non-matches.
+#' @export
+#' @examples
+#' str_view(c("abc", "def", "fgh"), "[aeiou]")
+#' str_view(c("abc", "def", "fgh"), "^")
+#' str_view(c("abc", "def", "fgh"), "..")
+#'
+#' # Show all matches with str_view_all
+#' str_view_all(c("abc", "def", "fgh"), "d|e")
+#'
+#' # Use match to control what is shown
+#' str_view(c("abc", "def", "fgh"), "d|e")
+#' str_view(c("abc", "def", "fgh"), "d|e", match = TRUE)
+#' str_view(c("abc", "def", "fgh"), "d|e", match = FALSE)
+str_view <- function(string, pattern, match = NA) {
+
+  if (identical(match, TRUE)) {
+    string <- string[str_detect(string, pattern)]
+  } else if (identical(match, FALSE)) {
+    string <- string[!str_detect(string, pattern)]
+  }
+
+  loc <- str_locate(string, pattern)
+
+  # How to do escaping? Need to update x and loc
+
+  has_match <- !is.na(loc[, "start"])
+  str_sub(string[has_match], loc[has_match, , drop = FALSE]) <-
+    paste0("<span class='match'>", str_sub(string[has_match], loc[has_match, , drop = FALSE]), "</span>")
+
+  bullets <- htmltools::HTML(str_c(
+    "<ul>\n",
+    str_c("  <li>", string, "</li>", collapse = "\n"),
+    "\n</ul>"
+  ))
+
+  htmlwidgets::createWidget("str_view", list(html = bullets),
+    sizingPolicy = htmlwidgets::sizingPolicy(
+      knitr.figure = FALSE,
+      defaultHeight = "auto"
+    ),
+    package = "stringr")
+}
+
+#' @rdname str_view
+#' @export
+str_view_all <- function(string, pattern, match = NA) {
+
+  if (identical(match, TRUE)) {
+    string <- string[str_detect(string, pattern)]
+  } else if (identical(match, FALSE)) {
+    string <- string[!str_detect(string, pattern)]
+  }
+
+  loc <- str_locate_all(string, pattern)
+
+  string_list <- Map(loc = loc, string = string, function(loc, string) {
+    if (nrow(loc) == 0)
+      return(string)
+
+    for (i in rev(seq_len(nrow(loc)))) {
+      str_sub(string, loc[i, , drop = FALSE]) <-
+        paste0("<span class='match'>", str_sub(string, loc[i, , drop = FALSE]), "</span>")
+    }
+    string
+  })
+  string <- unlist(string_list)
+
+  bullets <- htmltools::HTML(str_c(
+    "<ul>\n",
+    str_c("  <li>", string, "</li>", collapse = "\n"),
+    "\n</ul>"
+  ))
+
+  htmlwidgets::createWidget("str_view", list(html = bullets),
+    sizingPolicy = htmlwidgets::sizingPolicy(
+      knitr.figure = FALSE,
+      defaultHeight = "auto"
+    ),
+    package = "stringr")
+}
diff --git a/R/word.r b/R/word.r
index 3ffcbfa..12df866 100644
--- a/R/word.r
+++ b/R/word.r
@@ -44,6 +44,10 @@ word <- function(string, start = 1L, end = start, sep = fixed(" ")) {
   neg_end <- !is.na(end) & end < 0L
   end[neg_end] <- end[neg_end] + len[neg_end] + 1L
 
+  # Replace indexes past end with NA
+  start[start > len] <- NA
+  end[end > len] <- NA
+
   # Extract locations
   starts <- mapply(function(word, loc) word[loc, "start"], words, start)
   ends <-   mapply(function(word, loc) word[loc, "end"], words, end)
diff --git a/README.md b/README.md
index 818d8a5..834db5f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
 # stringr
 
-[![Build Status](https://travis-ci.org/hadley/stringr.png?branch=master)](https://travis-ci.org/hadley/stringr)
+[![Travis-CI Build Status](https://travis-ci.org/hadley/stringr.svg?branch=master)](https://travis-ci.org/hadley/stringr)
+[![Coverage Status](https://img.shields.io/codecov/c/github/hadley/stringr/master.svg)](https://codecov.io/github/hadley/stringr?branch=master)
+[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/stringr)](http://cran.r-project.org/package=stringr)
 
 Strings are not glamorous, high-profile components of R, but they do play a big role in many data cleaning and preparations tasks. R provides a solid set of string operations, but because they have grown organically over time, they can be inconsistent and a little hard to learn. Additionally, they lag behind the string operations in other programming languages, so that some things that are easy to do in languages like Ruby or Python are rather hard to do in R. 
 
@@ -31,7 +33,6 @@ To get the current development version from github:
 
 ```R
 # install.packages("devtools")
-devtools::install_github("Rexamine/stringi")
 devtools::install_github("hadley/stringr")
 ```
 
diff --git a/build/vignette.rds b/build/vignette.rds
index 24bc595..a644427 100644
Binary files a/build/vignette.rds and b/build/vignette.rds differ
diff --git a/data/fruit.rda b/data/fruit.rda
new file mode 100644
index 0000000..4ca3e1d
Binary files /dev/null and b/data/fruit.rda differ
diff --git a/data/sentences.rda b/data/sentences.rda
new file mode 100644
index 0000000..9bb9611
Binary files /dev/null and b/data/sentences.rda differ
diff --git a/data/words.rda b/data/words.rda
new file mode 100644
index 0000000..0b924bd
Binary files /dev/null and b/data/words.rda differ
diff --git a/inst/doc/stringr.Rmd b/inst/doc/stringr.Rmd
index 3e79e57..e20db2e 100644
--- a/inst/doc/stringr.Rmd
+++ b/inst/doc/stringr.Rmd
@@ -58,7 +58,7 @@ There are three string functions that are closely related to their base R equiva
     from the left of the last character. The end position defaults to `-1`, 
     which corresponds to the last character.
 
--   `str_str<-` is equivalent to `substr<-`, but like `str_sub` it understands 
+-   `str_sub<-` is equivalent to `substr<-`, but like `str_sub` it understands 
     negative indices, and replacement strings not do need to be the same length 
     as the string they are replacing.
 
@@ -145,7 +145,7 @@ phone <- "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"
 
 Each pattern matching function has the same first two arguments, a character vector of `string`s to process and a single `pattern` (regular expression) to match. The replace functions have an additional argument specifying the replacement string, and the split functions have an argument to specify the number of pieces.
 
-Unlike base string functions, stringr offers control over matching not through arguments, but through modifier functions, `regexp()`, `coll()` and `fixed()`.  This is a deliberate choice made to simplify these functions. For example, while `grepl` has six arguments, `str_detect()` only has two.
+Unlike base string functions, stringr offers control over matching not through arguments, but through modifier functions, `regex()`, `coll()` and `fixed()`.  This is a deliberate choice made to simplify these functions. For example, while `grepl` has six arguments, `str_detect()` only has two.
 
 ### Regular expressions
 
diff --git a/inst/doc/stringr.html b/inst/doc/stringr.html
index c133022..f44fa90 100644
--- a/inst/doc/stringr.html
+++ b/inst/doc/stringr.html
@@ -8,8 +8,10 @@
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <meta name="generator" content="pandoc" />
 
+<meta name="viewport" content="width=device-width, initial-scale=1">
 
-<meta name="date" content="2015-04-29" />
+
+<meta name="date" content="2016-08-19" />
 
 <title>Introduction to stringr</title>
 
@@ -17,32 +19,46 @@
 
 <style type="text/css">code{white-space: pre;}</style>
 <style type="text/css">
+div.sourceCode { overflow-x: auto; }
 table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
   margin: 0; padding: 0; vertical-align: baseline; border: none; }
 table.sourceCode { width: 100%; line-height: 100%; }
 td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
 td.sourceCode { padding-left: 5px; }
-code > span.kw { color: #007020; font-weight: bold; }
-code > span.dt { color: #902000; }
-code > span.dv { color: #40a070; }
-code > span.bn { color: #40a070; }
-code > span.fl { color: #40a070; }
-code > span.ch { color: #4070a0; }
-code > span.st { color: #4070a0; }
-code > span.co { color: #60a0b0; font-style: italic; }
-code > span.ot { color: #007020; }
-code > span.al { color: #ff0000; font-weight: bold; }
-code > span.fu { color: #06287e; }
-code > span.er { color: #ff0000; font-weight: bold; }
-</style>
-<style type="text/css">
-  pre:not([class]) {
-    background-color: white;
-  }
+code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
+code > span.dt { color: #902000; } /* DataType */
+code > span.dv { color: #40a070; } /* DecVal */
+code > span.bn { color: #40a070; } /* BaseN */
+code > span.fl { color: #40a070; } /* Float */
+code > span.ch { color: #4070a0; } /* Char */
+code > span.st { color: #4070a0; } /* String */
+code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
+code > span.ot { color: #007020; } /* Other */
+code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
+code > span.fu { color: #06287e; } /* Function */
+code > span.er { color: #ff0000; font-weight: bold; } /* Error */
+code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+code > span.cn { color: #880000; } /* Constant */
+code > span.sc { color: #4070a0; } /* SpecialChar */
+code > span.vs { color: #4070a0; } /* VerbatimString */
+code > span.ss { color: #bb6688; } /* SpecialString */
+code > span.im { } /* Import */
+code > span.va { color: #19177c; } /* Variable */
+code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+code > span.op { color: #666666; } /* Operator */
+code > span.bu { } /* BuiltIn */
+code > span.ex { } /* Extension */
+code > span.pp { color: #bc7a00; } /* Preprocessor */
+code > span.at { color: #7d9029; } /* Attribute */
+code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
+code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
 </style>
 
 
-<link href="data:text/css,body%20%7B%0A%20%20background%2Dcolor%3A%20%23fff%3B%0A%20%20margin%3A%201em%20auto%3B%0A%20%20max%2Dwidth%3A%20700px%3B%0A%20%20overflow%3A%20visible%3B%0A%20%20padding%2Dleft%3A%202em%3B%0A%20%20padding%2Dright%3A%202em%3B%0A%20%20font%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0A%20%20font%2Dsize%3A%2014px%3B%0A%20%20line%2Dheight%3A%201%2E35%3B%0A%7D%0A%0A%23header%20%7B%0A%20%20text%2Dalign%3A% [...]
+
+<link href="data:text/css;charset=utf-8,body%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0Amargin%3A%201em%20auto%3B%0Amax%2Dwidth%3A%20700px%3B%0Aoverflow%3A%20visible%3B%0Apadding%2Dleft%3A%202em%3B%0Apadding%2Dright%3A%202em%3B%0Afont%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E35%3B%0A%7D%0A%23header%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%23TOC%20%7B%0Aclear%3A%20bot [...]
 
 </head>
 
@@ -50,10 +66,10 @@ code > span.er { color: #ff0000; font-weight: bold; }
 
 
 
-<div id="header">
-<h1 class="title">Introduction to stringr</h1>
-<h4 class="date"><em>2015-04-29</em></h4>
-</div>
+
+<h1 class="title toc-ignore">Introduction to stringr</h1>
+<h4 class="date"><em>2016-08-19</em></h4>
+
 
 
 <p>Strings are not glamorous, high-profile components of R, but they do play a big role in many data cleaning and preparations tasks. R provides a solid set of string operations, but because they have grown organically over time, they can be inconsistent and a little hard to learn. Additionally, they lag behind the string operations in other programming languages, so that some things that are easy to do in languages like Ruby or Python are rather hard to do in R. The <strong>stringr</str [...]
@@ -78,7 +94,7 @@ code > span.er { color: #ff0000; font-weight: bold; }
 <li><p><code>str_c()</code> is equivalent to <code>paste()</code>, but it uses the empty string (“”) as the default separator and silently removes <code>NULL</code> inputs.</p></li>
 <li><p><code>str_length()</code> is equivalent to <code>nchar()</code>, but it preserves NA’s (rather than giving them length 2) and converts factors to characters (not integers).</p></li>
 <li><p><code>str_sub()</code> is equivalent to <code>substr()</code> but it returns a zero length vector if any of its inputs are zero length, and otherwise expands each argument to match the longest. It also accepts negative positions, which are calculated from the left of the last character. The end position defaults to <code>-1</code>, which corresponds to the last character.</p></li>
-<li><p><code>str_str<-</code> is equivalent to <code>substr<-</code>, but like <code>str_sub</code> it understands negative indices, and replacement strings not do need to be the same length as the string they are replacing.</p></li>
+<li><p><code>str_sub<-</code> is equivalent to <code>substr<-</code>, but like <code>str_sub</code> it understands negative indices, and replacement strings not do need to be the same length as the string they are replacing.</p></li>
 </ul>
 <p>Three functions add new functionality:</p>
 <ul>
@@ -90,24 +106,24 @@ code > span.er { color: #ff0000; font-weight: bold; }
 <div id="pattern-matching" class="section level2">
 <h2>Pattern matching</h2>
 <p>stringr provides pattern matching functions to <strong>detect</strong>, <strong>locate</strong>, <strong>extract</strong>, <strong>match</strong>, <strong>replace</strong>, and <strong>split</strong> strings. I’ll illustrate how they work with some strings and a regular expression designed to match (US) phone numbers:</p>
-<pre class="sourceCode r"><code class="sourceCode r">strings <-<span class="st"> </span><span class="kw">c</span>(
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">strings <-<span class="st"> </span><span class="kw">c</span>(
   <span class="st">"apple"</span>, 
   <span class="st">"219 733 8965"</span>, 
   <span class="st">"329-293-8753"</span>, 
   <span class="st">"Work: 579-499-7527; Home: 543.355.3679"</span>
 )
-phone <-<span class="st"> "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"</span></code></pre>
+phone <-<span class="st"> "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"</span></code></pre></div>
 <ul>
 <li><p><code>str_detect()</code> detects the presence or absence of a pattern and returns a logical vector (similar to <code>grepl()</code>). <code>str_subset()</code> returns the elements of a character vector that match a regular expression (similar to <code>grep()</code> with <code>value = TRUE</code>)`.</p>
-<pre class="sourceCode r"><code class="sourceCode r"><span class="co"># Which strings contain phone numbers?</span>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># Which strings contain phone numbers?</span>
 <span class="kw">str_detect</span>(strings, phone)
 <span class="co">#> [1] FALSE  TRUE  TRUE  TRUE</span>
 <span class="kw">str_subset</span>(strings, phone)
 <span class="co">#> [1] "219 733 8965"                          </span>
 <span class="co">#> [2] "329-293-8753"                          </span>
-<span class="co">#> [3] "Work: 579-499-7527; Home: 543.355.3679"</span></code></pre></li>
+<span class="co">#> [3] "Work: 579-499-7527; Home: 543.355.3679"</span></code></pre></div></li>
 <li><p><code>str_locate()</code> locates the first position of a pattern and returns a numeric matrix with columns start and end. <code>str_locate_all()</code> locates all matches, returning a list of numeric matrices. Similar to <code>regexpr()</code> and <code>gregexpr()</code>.</p>
-<pre class="sourceCode r"><code class="sourceCode r"><span class="co"># Where in the string is the phone number located?</span>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># Where in the string is the phone number located?</span>
 (loc <-<span class="st"> </span><span class="kw">str_locate</span>(strings, phone))
 <span class="co">#>      start end</span>
 <span class="co">#> [1,]    NA  NA</span>
@@ -129,9 +145,9 @@ phone <-<span class="st"> "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})
 <span class="co">#> [[4]]</span>
 <span class="co">#>      start end</span>
 <span class="co">#> [1,]     7  18</span>
-<span class="co">#> [2,]    27  38</span></code></pre></li>
+<span class="co">#> [2,]    27  38</span></code></pre></div></li>
 <li><p><code>str_extract()</code> extracts text corresponding to the first match, returning a character vector. <code>str_extract_all()</code> extracts all matches and returns a list of character vectors.</p>
-<pre class="sourceCode r"><code class="sourceCode r"><span class="co"># What are the phone numbers?</span>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># What are the phone numbers?</span>
 <span class="kw">str_extract</span>(strings, phone)
 <span class="co">#> [1] NA             "219 733 8965" "329-293-8753" "579-499-7527"</span>
 <span class="kw">str_extract_all</span>(strings, phone)
@@ -151,9 +167,9 @@ phone <-<span class="st"> "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})
 <span class="co">#> [1,] ""             ""            </span>
 <span class="co">#> [2,] "219 733 8965" ""            </span>
 <span class="co">#> [3,] "329-293-8753" ""            </span>
-<span class="co">#> [4,] "579-499-7527" "543.355.3679"</span></code></pre></li>
+<span class="co">#> [4,] "579-499-7527" "543.355.3679"</span></code></pre></div></li>
 <li><p><code>str_match()</code> extracts capture groups formed by <code>()</code> from the first match. It returns a character matrix with one column for the complete match and one column for each group. <code>str_match_all()</code> extracts capture groups from all matches and returns a list of character matrices. Similar to <code>regmatches()</code>.</p>
-<pre class="sourceCode r"><code class="sourceCode r"><span class="co"># Pull out the three components of the match</span>
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="co"># Pull out the three components of the match</span>
 <span class="kw">str_match</span>(strings, phone)
 <span class="co">#>      [,1]           [,2]  [,3]  [,4]  </span>
 <span class="co">#> [1,] NA             NA    NA    NA    </span>
@@ -175,9 +191,9 @@ phone <-<span class="st"> "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})
 <span class="co">#> [[4]]</span>
 <span class="co">#>      [,1]           [,2]  [,3]  [,4]  </span>
 <span class="co">#> [1,] "579-499-7527" "579" "499" "7527"</span>
-<span class="co">#> [2,] "543.355.3679" "543" "355" "3679"</span></code></pre></li>
+<span class="co">#> [2,] "543.355.3679" "543" "355" "3679"</span></code></pre></div></li>
 <li><p><code>str_replace()</code> replaces the first matched pattern and returns a character vector. <code>str_replace_all()</code> replaces all matches. Similar to <code>sub()</code> and <code>gsub()</code>.</p>
-<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">str_replace</span>(strings, phone, <span class="st">"XXX-XXX-XXXX"</span>)
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">str_replace</span>(strings, phone, <span class="st">"XXX-XXX-XXXX"</span>)
 <span class="co">#> [1] "apple"                                 </span>
 <span class="co">#> [2] "XXX-XXX-XXXX"                          </span>
 <span class="co">#> [3] "XXX-XXX-XXXX"                          </span>
@@ -186,13 +202,13 @@ phone <-<span class="st"> "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})
 <span class="co">#> [1] "apple"                                 </span>
 <span class="co">#> [2] "XXX-XXX-XXXX"                          </span>
 <span class="co">#> [3] "XXX-XXX-XXXX"                          </span>
-<span class="co">#> [4] "Work: XXX-XXX-XXXX; Home: XXX-XXX-XXXX"</span></code></pre></li>
+<span class="co">#> [4] "Work: XXX-XXX-XXXX; Home: XXX-XXX-XXXX"</span></code></pre></div></li>
 <li><p><code>str_split_fixed()</code> splits the string into a fixed number of pieces based on a pattern and returns a character matrix. <code>str_split()</code> splits a string into a variable number of pieces and returns a list of character vectors.</p></li>
 </ul>
 <div id="arguments" class="section level3">
 <h3>Arguments</h3>
 <p>Each pattern matching function has the same first two arguments, a character vector of <code>string</code>s to process and a single <code>pattern</code> (regular expression) to match. The replace functions have an additional argument specifying the replacement string, and the split functions have an argument to specify the number of pieces.</p>
-<p>Unlike base string functions, stringr offers control over matching not through arguments, but through modifier functions, <code>regexp()</code>, <code>coll()</code> and <code>fixed()</code>. This is a deliberate choice made to simplify these functions. For example, while <code>grepl</code> has six arguments, <code>str_detect()</code> only has two.</p>
+<p>Unlike base string functions, stringr offers control over matching not through arguments, but through modifier functions, <code>regex()</code>, <code>coll()</code> and <code>fixed()</code>. This is a deliberate choice made to simplify these functions. For example, while <code>grepl</code> has six arguments, <code>str_detect()</code> only has two.</p>
 </div>
 <div id="regular-expressions" class="section level3">
 <h3>Regular expressions</h3>
@@ -207,7 +223,7 @@ phone <-<span class="st"> "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})
 <div id="functions-that-return-lists" class="section level3">
 <h3>Functions that return lists</h3>
 <p>Many of the functions return a list of vectors or matrices. To work with each element of the list there are two strategies: iterate through a common set of indices, or use <code>Map()</code> to iterate through the vectors simultaneously. The second strategy is illustrated below:</p>
-<pre class="sourceCode r"><code class="sourceCode r">col2hex <-<span class="st"> </span>function(col) {
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">col2hex <-<span class="st"> </span>function(col) {
   rgb <-<span class="st"> </span><span class="kw">col2rgb</span>(col)
   <span class="kw">rgb</span>(rgb[<span class="st">"red"</span>, ], rgb[<span class="st">"green"</span>, ], rgb[<span class="st">"blue"</span>, ], <span class="dt">max =</span> <span class="dv">255</span>)
 }
@@ -236,14 +252,14 @@ locs <-<span class="st"> </span><span class="kw">str_locate_all</span>(string
 <span class="co">#> [2] "Roses are red, violets are #0000FF" </span>
 <span class="co">#> </span>
 <span class="co">#> $`My favourite colour is green`</span>
-<span class="co">#> [1] "My favourite colour is #00FF00"</span></code></pre>
+<span class="co">#> [1] "My favourite colour is #00FF00"</span></code></pre></div>
 <p>Another approach is to use the second form of <code>str_replace_all()</code>: if you give it a named vector, it applies each <code>pattern = replacement</code> in turn:</p>
-<pre class="sourceCode r"><code class="sourceCode r">matches <-<span class="st"> </span><span class="kw">col2hex</span>(<span class="kw">colors</span>())
+<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">matches <-<span class="st"> </span><span class="kw">col2hex</span>(<span class="kw">colors</span>())
 <span class="kw">names</span>(matches) <-<span class="st"> </span><span class="kw">str_c</span>(<span class="st">"</span><span class="ch">\\</span><span class="st">b"</span>, <span class="kw">colors</span>(), <span class="st">"</span><span class="ch">\\</span><span class="st">b"</span>)
 
 <span class="kw">str_replace_all</span>(strings, matches)
 <span class="co">#> [1] "Roses are #FF0000, violets are #0000FF"</span>
-<span class="co">#> [2] "My favourite colour is #00FF00"</span></code></pre>
+<span class="co">#> [2] "My favourite colour is #00FF00"</span></code></pre></div>
 </div>
 </div>
 <div id="conclusion" class="section level2">
diff --git a/inst/htmlwidgets/lib/str_view.css b/inst/htmlwidgets/lib/str_view.css
new file mode 100644
index 0000000..0cf22c7
--- /dev/null
+++ b/inst/htmlwidgets/lib/str_view.css
@@ -0,0 +1,11 @@
+.str_view ul, .str_view li {
+  list-style: none;
+  padding: 0;
+  margin: 0.5em 0;
+  font-family: monospace;
+}
+
+.str_view .match {
+  border: 1px solid #ccc;
+  background-color: #eee;
+}
diff --git a/inst/htmlwidgets/str_view.js b/inst/htmlwidgets/str_view.js
new file mode 100644
index 0000000..9e33abf
--- /dev/null
+++ b/inst/htmlwidgets/str_view.js
@@ -0,0 +1,17 @@
+HTMLWidgets.widget({
+
+  name: 'str_view',
+
+  type: 'output',
+
+  initialize: function(el, width, height) {
+  },
+
+  renderValue: function(el, x, instance) {
+    el.innerHTML = x.html;
+  },
+
+  resize: function(el, width, height, instance) {
+  }
+
+});
diff --git a/inst/htmlwidgets/str_view.yaml b/inst/htmlwidgets/str_view.yaml
new file mode 100644
index 0000000..1fbf498
--- /dev/null
+++ b/inst/htmlwidgets/str_view.yaml
@@ -0,0 +1,5 @@
+dependencies:
+ - name: str_view
+   version: 0.1.0
+   src: htmlwidgets/lib/
+   stylesheet: str_view.css
diff --git a/man/case.Rd b/man/case.Rd
index 92d56be..d32a9d0 100644
--- a/man/case.Rd
+++ b/man/case.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/case.R
 \name{case}
 \alias{case}
diff --git a/man/invert_match.Rd b/man/invert_match.Rd
index 92619f8..e2ec24a 100644
--- a/man/invert_match.Rd
+++ b/man/invert_match.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/locate.r
 \name{invert_match}
 \alias{invert_match}
diff --git a/man/modifier-deprecated.Rd b/man/modifier-deprecated.Rd
index 490d18e..0201ccd 100644
--- a/man/modifier-deprecated.Rd
+++ b/man/modifier-deprecated.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/modifiers.r
 \name{modifier-deprecated}
 \alias{ignore.case}
@@ -11,7 +11,7 @@ ignore.case(string)
 perl(pattern)
 }
 \description{
-Please use \code{\link{regexp}} and \code{\link{coll}} instead.
+Please use \code{\link{regex}} and \code{\link{coll}} instead.
 }
 \keyword{internal}
 
diff --git a/man/modifiers.Rd b/man/modifiers.Rd
index caeb126..732165f 100644
--- a/man/modifiers.Rd
+++ b/man/modifiers.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/modifiers.r
 \name{modifiers}
 \alias{boundary}
@@ -16,7 +16,7 @@ regex(pattern, ignore_case = FALSE, multiline = FALSE, comments = FALSE,
   dotall = FALSE, ...)
 
 boundary(type = c("character", "line_break", "sentence", "word"),
-  skip_word_none = TRUE, ...)
+  skip_word_none = NA, ...)
 }
 \arguments{
 \item{pattern}{Pattern to modify behaviour.}
@@ -43,14 +43,15 @@ default, only match the start and end of the input.}
 \item{type}{Boundary type to detect.}
 
 \item{skip_word_none}{Ignore "words" that don't contain any characters
-or numbers - i.e. punctuation.}
+or numbers - i.e. punctuation. Default \code{NA} will skip such "words"
+only when splitting on \code{word} boundaries.}
 }
 \description{
 \describe{
  \item{fixed}{Compare literal bytes in the string. This is very fast, but
    not usually what you want for non-ASCII character sets.}
  \item{coll}{Compare strings respecting standard collation rules.}
- \item{regexp}{The default. Uses ICU regular expressions.}
+ \item{regex}{The default. Uses ICU regular expressions.}
  \item{boundary}{Match boundaries between things.}
 }
 }
diff --git a/man/pipe.Rd b/man/pipe.Rd
index 08a8b06..e0bc900 100644
--- a/man/pipe.Rd
+++ b/man/pipe.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/utils.R
 \name{\%>\%}
 \alias{\%>\%}
diff --git a/man/str_c.Rd b/man/str_c.Rd
index bf60e13..a59757c 100644
--- a/man/str_c.Rd
+++ b/man/str_c.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/c.r
 \name{str_c}
 \alias{str_c}
@@ -6,12 +6,16 @@
 \title{Join multiple strings into a single string.}
 \usage{
 str_c(..., sep = "", collapse = NULL)
-
-str_join(..., sep = "", collapse = NULL)
 }
 \arguments{
 \item{...}{One or more character vectors. Zero length arguments
-are removed.}
+  are removed. Short arguments are recycled to the length of the
+  longest.
+
+  Like most other R functions, missing values are "infectious": whenever
+  a missing value is combined with another string the result will always
+  be missing. Use \code{\link{str_replace_na}} to convert \code{NA} to
+  \code{"NA"}}
 
 \item{sep}{String to insert between input vectors.}
 
@@ -48,6 +52,6 @@ str_c(str_replace_na(c("a", NA, "b")), "-d")
 }
 \seealso{
 \code{\link{paste}} for equivalent base R functionality, and
-   \code{\link[stringi]{stri_c}} which this function wraps
+   \code{\link[stringi]{stri_join}} which this function wraps
 }
 
diff --git a/man/str_conv.Rd b/man/str_conv.Rd
index 252d452..5233e50 100644
--- a/man/str_conv.Rd
+++ b/man/str_conv.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/conv.R
 \name{str_conv}
 \alias{str_conv}
diff --git a/man/str_count.Rd b/man/str_count.Rd
index 38cb61b..6d8f574 100644
--- a/man/str_count.Rd
+++ b/man/str_count.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/count.r
 \name{str_count}
 \alias{str_count}
diff --git a/man/str_detect.Rd b/man/str_detect.Rd
index afdad9b..fb9dfe2 100644
--- a/man/str_detect.Rd
+++ b/man/str_detect.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/detect.r
 \name{str_detect}
 \alias{str_detect}
diff --git a/man/str_dup.Rd b/man/str_dup.Rd
index 1d6b1c9..011824c 100644
--- a/man/str_dup.Rd
+++ b/man/str_dup.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/dup.r
 \name{str_dup}
 \alias{str_dup}
diff --git a/man/str_extract.Rd b/man/str_extract.Rd
index 6b35865..b3e1a09 100644
--- a/man/str_extract.Rd
+++ b/man/str_extract.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/extract.r
 \name{str_extract}
 \alias{str_extract}
@@ -52,10 +52,12 @@ str_extract_all(shopping_list, "\\\\d")
 # Simplify results into character matrix
 str_extract_all(shopping_list, "\\\\b[a-z]+\\\\b", simplify = TRUE)
 str_extract_all(shopping_list, "\\\\d", simplify = TRUE)
+
+# Extract all words
+str_extract_all("This is, suprisingly, a sentence.", boundary("word"))
 }
 \seealso{
-\code{\link[stringi]{stri_extract_first}} and
-  \code{\link[stringi]{stri_extract_all}} for the underlying
-  implementation.
+\code{\link{str_match}} to extract matched groups;
+  \code{\link[stringi]{stri_extract}} for the underlying implementation.
 }
 
diff --git a/man/str_interp.Rd b/man/str_interp.Rd
new file mode 100644
index 0000000..b70bef1
--- /dev/null
+++ b/man/str_interp.Rd
@@ -0,0 +1,62 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/interp.R
+\name{str_interp}
+\alias{str_interp}
+\title{String interpolation.}
+\usage{
+str_interp(string, env = parent.frame())
+}
+\arguments{
+\item{string}{A template character string. This function is not vectorised:
+a character vector will be collapsed into a single string.}
+
+\item{env}{The environment in which to evaluate the expressions.}
+}
+\value{
+An interpolated character string.
+}
+\description{
+String interpolation is a useful way of specifying a character string which
+depends on values in a certain environment. It allows for string creation
+which is easier to read and write when compared to using e.g.
+\code{\link{paste}} or \code{\link{sprintf}}. The (template) string can
+include expression placeholders of the form \code{${expression}} or
+\code{$[format]{expression}}, where expressions are valid R expressions that
+can be evaluated in the given environment, and \code{format} is a format
+specification valid for use with \code{\link{sprintf}}.
+}
+\examples{
+
+# Using values from the environment, and some formats
+user_name <- "smbache"
+amount <- 6.656
+account <- 1337
+str_interp("User ${user_name} (account $[08d]{account}) has $$[.2f]{amount}.")
+
+# Nested brace pairs work inside expressions too, and any braces can be
+# placed outside the expressions.
+str_interp("Works with } nested { braces too: $[.2f]{{{2 + 2}*{amount}}}")
+
+# Values can also come from a list
+str_interp(
+  "One value, ${value1}, and then another, ${value2*2}.",
+  list(value1 = 10, value2 = 20)
+)
+
+# Or a data frame
+str_interp(
+  "Values are $[.2f]{max(Sepal.Width)} and $[.2f]{min(Sepal.Width)}.",
+  iris
+)
+
+# Use a vector when the string is long:
+max_char <- 80
+str_interp(c(
+  "This particular line is so long that it is hard to write ",
+  "without breaking the ${max_char}-char barrier!"
+))
+}
+\author{
+Stefan Milton Bache
+}
+
diff --git a/man/str_length.Rd b/man/str_length.Rd
index 920c593..9df8a16 100644
--- a/man/str_length.Rd
+++ b/man/str_length.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/length.r
 \name{str_length}
 \alias{str_length}
diff --git a/man/str_locate.Rd b/man/str_locate.Rd
index 040809f..b6fc070 100644
--- a/man/str_locate.Rd
+++ b/man/str_locate.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/locate.r
 \name{str_locate}
 \alias{str_locate}
diff --git a/man/str_match.Rd b/man/str_match.Rd
index d332d51..56ac7d2 100644
--- a/man/str_match.Rd
+++ b/man/str_match.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/match.r
 \name{str_match}
 \alias{str_match}
@@ -37,6 +37,13 @@ str_match(strings, phone)
 # Extract/match all
 str_extract_all(strings, phone)
 str_match_all(strings, phone)
+
+x <- c("<a> <b>", "<a> <>", "<a>", "", NA)
+str_match(x, "<(.*?)> <(.*?)>")
+str_match_all(x, "<(.*?)>")
+
+str_extract(x, "<.*?>")
+str_extract_all(x, "<.*?>")
 }
 \seealso{
 \code{\link{str_extract}} to extract the complete match,
diff --git a/man/str_order.Rd b/man/str_order.Rd
index 90f3772..991be0f 100644
--- a/man/str_order.Rd
+++ b/man/str_order.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/sort.R
 \name{str_order}
 \alias{str_order}
diff --git a/man/str_pad.Rd b/man/str_pad.Rd
index 5ef8028..9dc833a 100644
--- a/man/str_pad.Rd
+++ b/man/str_pad.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/pad-trim.r
 \name{str_pad}
 \alias{str_pad}
@@ -37,6 +37,7 @@ str_pad("a", 10, pad = c("-", "_", " "))
 str_pad("hadley", 3)
 }
 \seealso{
-\code{\link{str_trim}} to remove whitespace
+\code{\link{str_trim}} to remove whitespace;
+  \code{\link{str_trunc}} to decrease the maximum width of a string.
 }
 
diff --git a/man/str_replace.Rd b/man/str_replace.Rd
index 6359c89..674d812 100644
--- a/man/str_replace.Rd
+++ b/man/str_replace.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/replace.r
 \name{str_replace}
 \alias{str_replace}
@@ -13,7 +13,7 @@ str_replace_all(string, pattern, replacement)
 \item{string}{Input vector. Either a character vector, or something
 coercible to one.}
 
-\item{pattern,replacement}{Supply separate pattern and replacement strings
+\item{pattern, replacement}{Supply separate pattern and replacement strings
   to vectorise over the patterns. References of the form \code{\1},
   \code{\2} will be replaced with the contents of the respective matched
   group (created by \code{()}) within the pattern.
diff --git a/man/str_replace_na.Rd b/man/str_replace_na.Rd
index 37e58cd..a4372fe 100644
--- a/man/str_replace_na.Rd
+++ b/man/str_replace_na.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/replace.r
 \name{str_replace_na}
 \alias{str_replace_na}
@@ -23,6 +23,6 @@ coercible to one.}
 Turn NA into "NA"
 }
 \examples{
-str_replace_na(c("NA", "abc", "def"))
+str_replace_na(c(NA, "abc", "def"))
 }
 
diff --git a/man/str_split.Rd b/man/str_split.Rd
index 84cc707..9a866d7 100644
--- a/man/str_split.Rd
+++ b/man/str_split.Rd
@@ -1,11 +1,11 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/split.r
 \name{str_split}
 \alias{str_split}
 \alias{str_split_fixed}
 \title{Split up a string into pieces.}
 \usage{
-str_split(string, pattern, n = Inf)
+str_split(string, pattern, n = Inf, simplify = FALSE)
 
 str_split_fixed(string, pattern, n)
 }
@@ -33,6 +33,9 @@ coercible to one.}
 
   For \code{str_split_fixed}, if n is greater than the number of pieces,
   the result will be padded with empty strings.}
+
+\item{simplify}{If \code{FALSE}, the default, returns a list of character
+vectors. If \code{TRUE} returns a character matrix.}
 }
 \value{
 For \code{str_split_fixed}, a character matrix with \code{n} columns.
@@ -48,6 +51,7 @@ fruits <- c(
 )
 
 str_split(fruits, " and ")
+str_split(fruits, " and ", simplify = TRUE)
 
 # Specify n to restrict the number of possible matches
 str_split(fruits, " and ", n = 3)
diff --git a/man/str_sub.Rd b/man/str_sub.Rd
index 597e238..5a4852b 100644
--- a/man/str_sub.Rd
+++ b/man/str_sub.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/sub.r
 \name{str_sub}
 \alias{str_sub}
@@ -12,7 +12,7 @@ str_sub(string, start = 1L, end = -1L) <- value
 \arguments{
 \item{string}{input character vector.}
 
-\item{start,end}{Two integer vectors. \code{start} gives the position
+\item{start, end}{Two integer vectors. \code{start} gives the position
   of the first character (defaults to first), \code{end} gives the position
   of the last (defaults to last character). Alternatively, pass a two-column
   matrix to \code{start}.
diff --git a/man/str_subset.Rd b/man/str_subset.Rd
index 91778ac..f0a255b 100644
--- a/man/str_subset.Rd
+++ b/man/str_subset.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/subset.R
 \name{str_subset}
 \alias{str_subset}
diff --git a/man/str_trim.Rd b/man/str_trim.Rd
index aa29289..ddd1eb8 100644
--- a/man/str_trim.Rd
+++ b/man/str_trim.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/pad-trim.r
 \name{str_trim}
 \alias{str_trim}
diff --git a/man/str_trunc.Rd b/man/str_trunc.Rd
new file mode 100644
index 0000000..ea2c72f
--- /dev/null
+++ b/man/str_trunc.Rd
@@ -0,0 +1,33 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/pad-trim.r
+\name{str_trunc}
+\alias{str_trunc}
+\title{Truncate a character string.}
+\usage{
+str_trunc(string, width, side = c("right", "left", "center"),
+  ellipsis = "...")
+}
+\arguments{
+\item{string}{A character vector.}
+
+\item{width}{Maximum width of string.}
+
+\item{side, ellipsis}{Location and content of ellipsis that indicates
+content has been removed.}
+}
+\description{
+Truncate a character string.
+}
+\examples{
+x <- "This string is moderately long"
+rbind(
+  str_trunc(x, 20, "right"),
+  str_trunc(x, 20, "left"),
+  str_trunc(x, 20, "center")
+)
+
+}
+\seealso{
+\code{\link{str_pad}} to increase the minimum width of a string.
+}
+
diff --git a/man/str_view.Rd b/man/str_view.Rd
new file mode 100644
index 0000000..dc642de
--- /dev/null
+++ b/man/str_view.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/view.R
+\name{str_view}
+\alias{str_view}
+\alias{str_view_all}
+\title{View HTML rendering of regular expression match.}
+\usage{
+str_view(string, pattern, match = NA)
+
+str_view_all(string, pattern, match = NA)
+}
+\arguments{
+\item{string}{Input vector. Either a character vector, or something
+coercible to one.}
+
+\item{pattern}{Pattern to look for.
+
+  The default interpretation is a regular expression, as described
+  in \link[stringi]{stringi-search-regex}. Control options with
+  \code{\link{regex}()}.
+
+  Match a fixed string (i.e. by comparing only bytes), using
+  \code{\link{fixed}(x)}. This is fast, but approximate. Generally,
+  for matching human text, you'll want \code{\link{coll}(x)} which
+  respects character matching rules for the specified locale.
+
+  Match character, word, line and sentence boundaries with
+  \code{\link{boundary}()}. An empty pattern, "", is equivalent to
+  \code{boundary("character")}.}
+
+\item{match}{If \code{TRUE}, shows only strings that match the pattern.
+If \code{FALSE}, shows only the strings that don't match the pattern.
+Otherwise (the default, \code{NA}) displays both matches and non-matches.}
+}
+\description{
+\code{str_view} shows the first match; \code{str_view_all} shows all
+the matches.
+}
+\examples{
+str_view(c("abc", "def", "fgh"), "[aeiou]")
+str_view(c("abc", "def", "fgh"), "^")
+str_view(c("abc", "def", "fgh"), "..")
+
+# Show all matches with str_view_all
+str_view_all(c("abc", "def", "fgh"), "d|e")
+
+# Use match to control what is shown
+str_view(c("abc", "def", "fgh"), "d|e")
+str_view(c("abc", "def", "fgh"), "d|e", match = TRUE)
+str_view(c("abc", "def", "fgh"), "d|e", match = FALSE)
+}
+
diff --git a/man/str_wrap.Rd b/man/str_wrap.Rd
index c2a68b3..345aeed 100644
--- a/man/str_wrap.Rd
+++ b/man/str_wrap.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/wrap.r
 \name{str_wrap}
 \alias{str_wrap}
diff --git a/man/stringr-data.Rd b/man/stringr-data.Rd
new file mode 100644
index 0000000..95a5e83
--- /dev/null
+++ b/man/stringr-data.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/data.R
+\docType{data}
+\name{stringr-data}
+\alias{fruit}
+\alias{sentences}
+\alias{stringr-data}
+\alias{words}
+\title{Sample character vectors for practicing string manipulations.}
+\format{A character vector.}
+\usage{
+sentences
+
+fruit
+
+words
+}
+\description{
+\code{fruit} and \code{word} come from the \code{rcorpora} package
+written by Gabor Csardi; the data was collected by Darius Kazemi
+and made available at \url{https://github.com/dariusk/corpora}.
+\code{sentences} is a collection of "Harvard sentences" used for
+standardised testing of voice.
+}
+\examples{
+length(sentences)
+sentences[1:5]
+
+length(fruit)
+fruit[1:5]
+
+length(words)
+words[1:5]
+}
+\keyword{datasets}
+
diff --git a/man/stringr.Rd b/man/stringr.Rd
deleted file mode 100644
index a49955d..0000000
--- a/man/stringr.Rd
+++ /dev/null
@@ -1,9 +0,0 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
-% Please edit documentation in R/stringr.R
-\name{stringr}
-\alias{stringr}
-\title{Fast and friendly string manipulation.}
-\description{
-Fast and friendly string manipulation.
-}
-
diff --git a/man/word.Rd b/man/word.Rd
index 02642e8..3e56105 100644
--- a/man/word.Rd
+++ b/man/word.Rd
@@ -1,4 +1,4 @@
-% Generated by roxygen2 (4.1.0): do not edit by hand
+% Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/word.r
 \name{word}
 \alias{word}
diff --git a/tests/testthat/test-detect.r b/tests/testthat/test-detect.r
index 99fc429..2663e0c 100644
--- a/tests/testthat/test-detect.r
+++ b/tests/testthat/test-detect.r
@@ -1,22 +1,22 @@
 context("Detecting patterns")
 
 test_that("special cases are correct", {
-  expect_that(str_detect(NA, "x"), equals(NA))
-  expect_that(str_detect(character(), "x"), equals(logical()))
+  expect_equal(str_detect(NA, "x"), NA)
+  expect_equal(str_detect(character(), "x"), logical())
 })
 
 test_that("vectorised patterns work", {
-  expect_that(str_detect("ab", c("a", "b", "c")), equals(c(T, T, F)))
-  expect_that(str_detect(c("ca", "ab"), c("a", "c")), equals(c(T, F)))
+  expect_equal(str_detect("ab", c("a", "b", "c")), c(T, T, F))
+  expect_equal(str_detect(c("ca", "ab"), c("a", "c")), c(T, F))
 })
 
 test_that("modifiers work", {
-  expect_that(str_detect("ab", "AB"), equals(FALSE))
-  expect_that(str_detect("ab", regex("AB", TRUE)), equals(TRUE))
+  expect_false(str_detect("ab", "AB"))
+  expect_true(str_detect("ab", regex("AB", TRUE)))
 
-  expect_that(str_detect("abc", "ab[c]"), equals(TRUE))
-  expect_that(str_detect("abc", fixed("ab[c]")), equals(FALSE))
-  expect_that(str_detect("ab[c]", fixed("ab[c]")), equals(TRUE))
+  expect_true(str_detect("abc", "ab[c]"))
+  expect_false(str_detect("abc", fixed("ab[c]")))
+  expect_true(str_detect("ab[c]", fixed("ab[c]")))
 
-  expect_that(str_detect("abc", "(?x)a b c"), equals(TRUE))
+  expect_true(str_detect("abc", "(?x)a b c"))
 })
diff --git a/tests/testthat/test-dup.r b/tests/testthat/test-dup.r
index 4932648..ba98880 100644
--- a/tests/testthat/test-dup.r
+++ b/tests/testthat/test-dup.r
@@ -1,13 +1,13 @@
 context("Duplicating strings")
 
 test_that("basic duplication works", {
-  expect_that(str_dup("a", 3), equals("aaa"))
-  expect_that(str_dup("abc", 2), equals("abcabc"))
-  expect_that(str_dup(c("a", "b"), 2), equals(c("aa", "bb")))
-  expect_that(str_dup(c("a", "b"), c(2, 3)), equals(c("aa", "bbb")))
+  expect_equal(str_dup("a", 3), "aaa")
+  expect_equal(str_dup("abc", 2), "abcabc")
+  expect_equal(str_dup(c("a", "b"), 2), c("aa", "bb"))
+  expect_equal(str_dup(c("a", "b"), c(2, 3)), c("aa", "bbb"))
 })
 
 test_that("0 duplicates equals empty string", {
-  expect_that(str_dup("a", 0), equals(""))
-  expect_that(str_dup(c("a", "b"), 0), equals(rep("", 2)))
+  expect_equal(str_dup("a", 0), "")
+  expect_equal(str_dup(c("a", "b"), 0), rep("", 2))
 })
diff --git a/tests/testthat/test-extract.r b/tests/testthat/test-extract.r
index ebc0c1e..e13254d 100644
--- a/tests/testthat/test-extract.r
+++ b/tests/testthat/test-extract.r
@@ -3,13 +3,15 @@ context("Extract patterns")
 test_that("single pattern extracted correctly", {
   test <- c("one two three", "a b c")
 
-  expect_that(
+  expect_equal(
     str_extract_all(test, "[a-z]+"),
-    equals(list(c("one", "two", "three"), c("a", "b", "c"))))
+    list(c("one", "two", "three"), c("a", "b", "c"))
+  )
 
-  expect_that(
+  expect_equal(
     str_extract_all(test, "[a-z]{3,}"),
-    equals(list(c("one", "two", "three"), character())))
+    list(c("one", "two", "three"), character())
+  )
 
 })
 
diff --git a/tests/testthat/test-interp.r b/tests/testthat/test-interp.r
new file mode 100644
index 0000000..ad9aa8e
--- /dev/null
+++ b/tests/testthat/test-interp.r
@@ -0,0 +1,66 @@
+context("String Interpolation")
+
+test_that("str_interp works with default env", {
+  subject <- "statistics"
+  number  <- 7
+  floating <- 6.656
+
+  expect_equal(
+    str_interp("A ${subject}. B $[d]{number}. C $[.2f]{floating}."),
+    "A statistics. B 7. C 6.66."
+  )
+
+  expect_equal(
+    str_interp("Pi is approximately $[.5f]{pi}"),
+    "Pi is approximately 3.14159"
+  )
+})
+
+test_that("str_interp works with lists and data frames.", {
+  expect_equal(
+    str_interp(
+      "One value, ${value1}, and then another, ${value2*2}.",
+      list(value1 = 10, value2 = 20)
+    ),
+    "One value, 10, and then another, 40."
+  )
+
+  expect_equal(
+    str_interp(
+      "Values are $[.2f]{max(Sepal.Width)} and $[.2f]{min(Sepal.Width)}.",
+      iris
+    ),
+    "Values are 4.40 and 2.00."
+  )
+})
+
+test_that("str_interp works with nested expressions", {
+  amount <- 1337
+
+  expect_equal(
+    str_interp("Works with } nested { braces too: $[.2f]{{{2 + 2}*{amount}}}"),
+    "Works with } nested { braces too: 5348.00"
+  )
+})
+
+test_that("str_interp works in the absense of placeholders", {
+  expect_equal(
+    str_interp("A quite static string here."),
+    "A quite static string here."
+  )
+})
+
+test_that("str_interp fails when encountering nested placeholders", {
+  msg  <- "This will never see the light of day"
+  num  <- 1.2345
+
+  expect_error(
+    str_interp("${${msg}}"),
+    "Invalid template string for interpolation"
+  )
+
+  expect_error(
+    str_interp("$[.2f]{${msg}}"),
+    "Invalid template string for interpolation"
+  )
+})
diff --git a/tests/testthat/test-join.r b/tests/testthat/test-join.r
index c7bf803..f7f61f3 100644
--- a/tests/testthat/test-join.r
+++ b/tests/testthat/test-join.r
@@ -3,9 +3,9 @@ context("Joining strings")
 test_that("basic case works", {
   test <- c("a", "b", "c")
 
-  expect_that(str_c(test), equals(test))
-  expect_that(str_c(test, sep = " "), equals(test))
-  expect_that(str_c(test, collapse = ""), equals("abc"))
+  expect_equal(str_c(test), test)
+  expect_equal(str_c(test, sep = " "), test)
+  expect_equal(str_c(test, collapse = ""), "abc")
 })
 
 test_that("NULLs are dropped", {
diff --git a/tests/testthat/test-length.r b/tests/testthat/test-length.r
index aabc2f3..9a14b26 100644
--- a/tests/testthat/test-length.r
+++ b/tests/testthat/test-length.r
@@ -1,19 +1,19 @@
 context("String length")
 
 test_that("str_length is number of characters", {
-  expect_that(str_length("a"), equals(1))
-  expect_that(str_length("ab"), equals(2))
-  expect_that(str_length("abc"), equals(3))
+  expect_equal(str_length("a"), 1)
+  expect_equal(str_length("ab"), 2)
+  expect_equal(str_length("abc"), 3)
 })
 
 test_that("str_length of missing string is missing", {
-  expect_that(str_length(NA), equals(NA_integer_))
-  expect_that(str_length(c(NA, 1)), equals(c(NA, 1)))
-  expect_that(str_length("NA"), equals(2))
+  expect_equal(str_length(NA), NA_integer_)
+  expect_equal(str_length(c(NA, 1)), c(NA, 1))
+  expect_equal(str_length("NA"), 2)
 })
 
 test_that("str_length of factor is length of level", {
-  expect_that(str_length(factor("a")), equals(1))
-  expect_that(str_length(factor("ab")), equals(2))
-  expect_that(str_length(factor("abc")), equals(3))
+  expect_equal(str_length(factor("a")), 1)
+  expect_equal(str_length(factor("ab")), 2)
+  expect_equal(str_length(factor("abc")), 3)
 })
diff --git a/tests/testthat/test-locate.r b/tests/testthat/test-locate.r
index e5da63f..c065777 100644
--- a/tests/testthat/test-locate.r
+++ b/tests/testthat/test-locate.r
@@ -1,37 +1,33 @@
 context("Locations")
 
 test_that("basic location matching works", {
-  expect_that(str_locate("abc", "a")[1, ], equals(c(1, 1),
-    check.attributes = F))
-  expect_that(str_locate("abc", "b")[1, ], equals(c(2, 2),
-    check.attributes = F))
-  expect_that(str_locate("abc", "c")[1, ], equals(c(3, 3),
-    check.attributes = F))
-
-  expect_that(str_locate("abc", ".+")[1, ], equals(c(1, 3),
-    check.attributes = F))
+  expect_equivalent(str_locate("abc", "a")[1, ], c(1, 1))
+  expect_equivalent(str_locate("abc", "b")[1, ], c(2, 2))
+  expect_equivalent(str_locate("abc", "c")[1, ], c(3, 3))
+
+  expect_equivalent(str_locate("abc", ".+")[1, ], c(1, 3))
 })
 
 test_that("locations are integers", {
   strings <- c("a b c", "d e f")
-  expect_that(is.integer(str_locate(strings, "[a-z]")), is_true())
+  expect_true(is.integer(str_locate(strings, "[a-z]")))
 
   res <- str_locate_all(strings, "[a-z]")[[1]]
-  expect_that(is.integer(res), is_true())
-  expect_that(is.integer(invert_match(res)), is_true())
+  expect_true(is.integer(res))
+  expect_true(is.integer(invert_match(res)))
 })
 
 test_that("both string and patterns are vectorised", {
   strings <- c("abc", "def")
 
   locs <- str_locate(strings, "a")
-  expect_that(locs[, "start"], equals(c(1, NA)))
+  expect_equal(locs[, "start"], c(1, NA))
 
   locs <- str_locate(strings, c("a", "d"))
-  expect_that(locs[, "start"], equals(c(1, 1)))
-  expect_that(locs[, "end"],   equals(c(1, 1)))
+  expect_equal(locs[, "start"], c(1, 1))
+  expect_equal(locs[, "end"],   c(1, 1))
 
   locs <- str_locate_all(c("abab"), c("a", "b"))
-  expect_that(locs[[1]][, "start"], equals(c(1, 3)))
-  expect_that(locs[[2]][, "start"], equals(c(2, 4)))
+  expect_equal(locs[[1]][, "start"], c(1, 3))
+  expect_equal(locs[[2]][, "start"], c(2, 4))
 })
diff --git a/tests/testthat/test-match.r b/tests/testthat/test-match.r
index 33c31e2..bbf43df 100644
--- a/tests/testthat/test-match.r
+++ b/tests/testthat/test-match.r
@@ -1,7 +1,7 @@
 context("Matching groups")
 
 set.seed(1410)
-num <- matrix(sample(9, 10 * 10, rep = T), ncol = 10)
+num <- matrix(sample(9, 10 * 10, replace = T), ncol = 10)
 num_flat <- apply(num, 1, str_c, collapse = "")
 
 phones <- str_c(
@@ -17,33 +17,33 @@ test_that("special case are correct", {
 test_that("no matching cases returns 1 column matrix", {
   res <- str_match(c("a", "b"), ".")
 
-  expect_that(nrow(res), equals(2))
-  expect_that(ncol(res), equals(1))
+  expect_equal(nrow(res), 2)
+  expect_equal(ncol(res), 1)
 
-  expect_that(res[, 1], equals(c("a", "b")))
+  expect_equal(res[, 1], c("a", "b"))
 })
 
 test_that("single match works when all match", {
   matches <- str_match(phones, "\\(([0-9]{3})\\) ([0-9]{3}) ([0-9]{4})")
 
-  expect_that(nrow(matches), equals(length(phones)))
-  expect_that(ncol(matches), equals(4))
+  expect_equal(nrow(matches), length(phones))
+  expect_equal(ncol(matches), 4)
 
-  expect_that(matches[, 1], equals(phones))
+  expect_equal(matches[, 1], phones)
 
   matches_flat <- apply(matches[, -1], 1, str_c, collapse = "")
-  expect_that(matches_flat, equals(num_flat))
+  expect_equal(matches_flat, num_flat)
 })
 
 test_that("match returns NA when some inputs don't match", {
   matches <- str_match(c(phones, "blah", NA),
     "\\(([0-9]{3})\\) ([0-9]{3}) ([0-9]{4})")
 
-  expect_that(nrow(matches), equals(length(phones) + 2))
-  expect_that(ncol(matches), equals(4))
+  expect_equal(nrow(matches), length(phones) + 2)
+  expect_equal(ncol(matches), 4)
 
-  expect_that(matches[11, ], equals(rep(NA_character_, 4)))
-  expect_that(matches[12, ], equals(rep(NA_character_, 4)))
+  expect_equal(matches[11, ], rep(NA_character_, 4))
+  expect_equal(matches[12, ], rep(NA_character_, 4))
 })
 
 test_that("match returns NA when optional group doesn't match", {
@@ -57,5 +57,5 @@ test_that("multiple match works", {
   single_matches <- str_match(phones,
     "\\(([0-9]{3})\\) ([0-9]{3}) ([0-9]{4})")
 
-  expect_that(multi_match[[1]], equals(single_matches))
+  expect_equal(multi_match[[1]], single_matches)
 })
diff --git a/tests/testthat/test-pad.r b/tests/testthat/test-pad.r
index 06a38be..78e7af5 100644
--- a/tests/testthat/test-pad.r
+++ b/tests/testthat/test-pad.r
@@ -3,18 +3,18 @@ context("Test padding")
 test_that("long strings are unchanged", {
   lengths <- sample(40:100, 10)
   strings <- vapply(lengths, function(x)
-    str_c(letters[sample(26, x, rep = T)], collapse = ""),
+    str_c(letters[sample(26, x, replace = T)], collapse = ""),
     character(1))
 
   padded <- str_pad(strings, width = 30)
-  expect_that(str_length(padded), equals(str_length(padded)))
+  expect_equal(str_length(padded), str_length(padded))
 })
 
 test_that("directions work for simple case", {
 
   pad <- function(direction) str_pad("had", direction, width = 10)
 
-  expect_that(pad("right"),  equals("had       "))
-  expect_that(pad("left"),   equals("       had"))
-  expect_that(pad("both"),   equals("   had    "))
+  expect_equal(pad("right"),  "had       ")
+  expect_equal(pad("left"),   "       had")
+  expect_equal(pad("both"),   "   had    ")
 })
diff --git a/tests/testthat/test-replace.r b/tests/testthat/test-replace.r
new file mode 100644
index 0000000..438d8ba
--- /dev/null
+++ b/tests/testthat/test-replace.r
@@ -0,0 +1,57 @@
+context("Replacements")
+
+test_that("basic replacement works", {
+  expect_equal(str_replace_all("abababa", "ba", "BA"), "aBABABA")
+  expect_equal(str_replace("abababa", "ba", "BA"), "aBAbaba")
+})
+
+test_that("replacement strings with capture groups refs and dollar signs work", {
+  expect_equal(str_replace_all("abc$a$1$2", fixed("a"), "$1"), "$1bc$$1$1$2")
+  expect_equal(str_replace("abc$a$1$2", fixed("a"), "$1"), "$1bc$a$1$2")
+
+  expect_equal(str_replace_all("abcde", "(b)(c)(d)", "\\1"), "abe")
+  expect_equal(str_replace_all("abcde", "(b)(c)(d)", "\\2"), "ace")
+  expect_equal(str_replace_all("abcde", "(b)(c)(d)", "\\3"), "ade")
+
+  # gsub("(b)(c)(d)", "\\0", "abcde", perl=TRUE) gives a0e,
+  # in ICU regex $0 refers to the whole pattern match
+  expect_equal(str_replace_all("abcde", "(b)(c)(d)", "\\0"), "abcde")
+
+  # gsub("(b)(c)(d)", "\\4", "abcde", perl=TRUE) is legal,
+  # in ICU regex this gives an U_INDEX_OUTOFBOUNDS_ERROR
+  expect_error(
+    str_replace_all("abcde", "(b)(c)(d)", "\\4"),
+    "index that is out of bounds"
+  )
+
+  expect_equal(str_replace_all("abcde", "bcd", "\\\\1"), "a\\1e")
+
+  expect_equal(str_replace_all("a!1!2!b", "!", "$"), "a$1$2$b")
+  expect_equal(str_replace("aba", "b", "$"), "a$a")
+  expect_equal(str_replace("aba", "b", "$$$"), "a$$$a")
+  expect_equal(str_replace("aba", "(b)", "\\1$\\1$\\1"), "ab$b$ba")
+  expect_equal(str_replace("aba", "(b)", "\\1$\\\\1$\\1"), "ab$\\1$ba")
+  expect_equal(str_replace("aba", "(b)", "\\\\1$\\1$\\\\1"), "a\\1$b$\\1a")
+})
+
+test_that("can replace multiple matches", {
+  x <- c("a1", "b2")
+  y <- str_replace_all(x, c("a" = "1", "b" = "2"))
+  expect_equal(y, c("11", "22"))
+})
+
+# fix_replacement ---------------------------------------------------------
+
+test_that("$ are escaped", {
+  expect_equal(fix_replacement("$"), "\\$")
+  expect_equal(fix_replacement("\\$"), "\\\\$")
+})
+
+test_that("\1 converted to $1 etc", {
+  expect_equal(fix_replacement("\\1"), "$1")
+  expect_equal(fix_replacement("\\9"), "$9")
+})
+
+test_that("\\1 left as is", {
+  expect_equal(fix_replacement("\\\\1"), "\\\\1")
+})
diff --git a/tests/testthat/test-split.r b/tests/testthat/test-split.r
index 942bf9e..86922a7 100644
--- a/tests/testthat/test-split.r
+++ b/tests/testthat/test-split.r
@@ -1,69 +1,82 @@
 context("Splitting strings")
 
 test_that("special cases are correct", {
-  expect_that(str_split(NA, "")[[1]], equals(NA_character_))
-  expect_that(str_split(character(), ""), equals(list()))
+  expect_equal(str_split(NA, "")[[1]], NA_character_)
+  expect_equal(str_split(character(), ""), list())
 })
 
 test_that("str_split functions as expected", {
   test <- c("bab", "cac", "dadad")
   result <- str_split(test, "a")
 
-  expect_that(result, is_a("list"))
-  expect_that(length(result), equals(3))
+  expect_is(result, "list")
+  expect_equal(length(result), 3)
 
   lengths <- vapply(result, length, integer(1))
-  expect_that(lengths, equals(c(2, 2, 3)))
+  expect_equal(lengths, c(2, 2, 3))
 
-  expect_that(result, equals(
-    list(c("b", "b"), c("c", "c"), c("d", "d", "d"))))
+  expect_equal(result,
+    list(c("b", "b"), c("c", "c"), c("d", "d", "d"))
+  )
 })
 
 test_that("vectors give correct results dealt with correctly", {
   test <- c("bab", "cac", "dadad", "eae")
   result <- str_split_fixed(test, "a", 3)
 
-  expect_that(result, is_a("matrix"))
-  expect_that(nrow(result), equals(4))
-  expect_that(ncol(result), equals(3))
-
-  expect_that(result[1, ], equals(c("b", "b", "")))
-  expect_that(result[3, ], equals(c("d", "d", "d")))
-  expect_that(result[, 1], equals(c("b", "c", "d", "e")))
+  expect_is(result, "matrix")
+  expect_equal(nrow(result), 4)
+  expect_equal(ncol(result), 3)
 
+  expect_equal(result[1, ], c("b", "b", ""))
+  expect_equal(result[3, ], c("d", "d", "d"))
+  expect_equal(result[, 1], c("b", "c", "d", "e"))
 })
 
 test_that("n sets maximum number of splits in str_split", {
   test <- "Subject: Roger: his drinking problems"
 
-  expect_that(length(str_split(test, ": ")[[1]]), equals(3))
-  expect_that(length(str_split(test, ": ", 4)[[1]]), equals(3))
-  expect_that(length(str_split(test, ": ", 3)[[1]]), equals(3))
-  expect_that(length(str_split(test, ": ", 2)[[1]]), equals(2))
-  expect_that(length(str_split(test, ": ", 1)[[1]]), equals(1))
+  expect_equal(length(str_split(test, ": ")[[1]]), 3)
+  expect_equal(length(str_split(test, ": ", 4)[[1]]), 3)
+  expect_equal(length(str_split(test, ": ", 3)[[1]]), 3)
+  expect_equal(length(str_split(test, ": ", 2)[[1]]), 2)
+  expect_equal(length(str_split(test, ": ", 1)[[1]]), 1)
 
-  expect_that(
+  expect_equal(
     str_split(test, ": ", 3)[[1]],
-    equals(c("Subject", "Roger", "his drinking problems")))
-  expect_that(
+    c("Subject", "Roger", "his drinking problems")
+  )
+  expect_equal(
     str_split(test, ": ", 2)[[1]],
-    equals(c("Subject", "Roger: his drinking problems")))
+    c("Subject", "Roger: his drinking problems")
+  )
 
 })
 
 test_that("n sets exact number of splits in str_split_fixed", {
   test <- "Subject: Roger: his drinking problems"
 
-  expect_that(ncol(str_split_fixed(test, ": ", 4)), equals(4))
-  expect_that(ncol(str_split_fixed(test, ": ", 3)), equals(3))
-  expect_that(ncol(str_split_fixed(test, ": ", 2)), equals(2))
-  expect_that(ncol(str_split_fixed(test, ": ", 1)), equals(1))
+  expect_equal(ncol(str_split_fixed(test, ": ", 4)), 4)
+  expect_equal(ncol(str_split_fixed(test, ": ", 3)), 3)
+  expect_equal(ncol(str_split_fixed(test, ": ", 2)), 2)
+  expect_equal(ncol(str_split_fixed(test, ": ", 1)), 1)
 
-  expect_that(
+  expect_equal(
     str_split_fixed(test, ": ", 3)[1, ],
-    equals(c("Subject", "Roger", "his drinking problems")))
-  expect_that(
+    c("Subject", "Roger", "his drinking problems")
+  )
+  expect_equal(
     str_split_fixed(test, ": ", 2)[1, ],
-    equals(c("Subject", "Roger: his drinking problems")))
+    c("Subject", "Roger: his drinking problems")
+  )
+
+})
 
+test_that("str_split can split sentences correctly", {
+ test <- "This is a sentence. Is this a sentence? Why, yes it is."
+ expect_equal(length(str_split(test, boundary("sentence"))[[1]]), 3)
+ expect_equal(
+   str_split(test, boundary("sentence")),
+   list(c("This is a sentence. ", "Is this a sentence? ", "Why, yes it is."))
+  )
 })
diff --git a/tests/testthat/test-sub.r b/tests/testthat/test-sub.r
index df7db7f..92c8733 100644
--- a/tests/testthat/test-sub.r
+++ b/tests/testthat/test-sub.r
@@ -2,71 +2,73 @@ context("Extracting substrings")
 alphabet <- str_c(letters, collapse = "")
 
 test_that("correct substring extracted", {
-  expect_that(str_sub(alphabet, 1, 3), equals("abc"))
-  expect_that(str_sub(alphabet, 24, 26), equals("xyz"))
+  expect_equal(str_sub(alphabet, 1, 3), "abc")
+  expect_equal(str_sub(alphabet, 24, 26), "xyz")
 })
 
 test_that("arguments expanded to longest", {
   alphabet <- str_c(letters, collapse = "")
 
-  expect_that(
+  expect_equal(
     str_sub(alphabet, c(1, 24), c(3, 26)),
-    equals(c("abc", "xyz")))
+    c("abc", "xyz")
+  )
 
-  expect_that(
+  expect_equal(
     str_sub(c("abc", "xyz"), 2, 2),
-    equals(c("b", "y")))
+    c("b", "y")
+  )
 })
 
 
 test_that("specifying only end subsets from start", {
-  expect_that(str_sub(alphabet, end = 3), equals(c("abc")))
+  expect_equal(str_sub(alphabet, end = 3), "abc")
 })
 
 test_that("specifying only start subsets to end", {
-  expect_that(str_sub(alphabet, 24), equals(c("xyz")))
+  expect_equal(str_sub(alphabet, 24), "xyz")
 })
 
 test_that("specifying -1 as end selects entire string", {
-  expect_that(
+  expect_equal(
     str_sub("ABCDEF", c(4, 5), c(5, -1)),
-    equals(c("DE", "EF"))
+    c("DE", "EF")
   )
 
-  expect_that(
+  expect_equal(
     str_sub("ABCDEF", c(4, 5), c(-1, -1)),
-    equals(c("DEF", "EF"))
+    c("DEF", "EF")
   )
 })
 
 test_that("negative values select from end", {
-  expect_that(str_sub("ABCDEF", 1, -4), equals("ABC"))
-  expect_that(str_sub("ABCDEF", -3), equals("DEF"))
+  expect_equal(str_sub("ABCDEF", 1, -4), "ABC")
+  expect_equal(str_sub("ABCDEF", -3), "DEF")
 })
 
 test_that("missing arguments give missing results", {
-  expect_that(str_sub(NA), equals(NA_character_))
-  expect_that(str_sub(NA, 1, 3), equals(NA_character_))
-  expect_that(str_sub(c(NA, "NA"), 1, 3), equals(c(NA, "NA")))
+  expect_equal(str_sub(NA), NA_character_)
+  expect_equal(str_sub(NA, 1, 3), NA_character_)
+  expect_equal(str_sub(c(NA, "NA"), 1, 3), c(NA, "NA"))
 
-  expect_that(str_sub("test", NA, NA), equals(NA_character_))
-  expect_that(str_sub(c(NA, "test"), NA, NA), equals(rep(NA_character_, 2)))
+  expect_equal(str_sub("test", NA, NA), NA_character_)
+  expect_equal(str_sub(c(NA, "test"), NA, NA), rep(NA_character_, 2))
 
 })
 
 test_that("replacement works", {
   x <- "BBCDEF"
   str_sub(x, 1, 1) <- "A"
-  expect_that(x, equals("ABCDEF"))
+  expect_equal(x, "ABCDEF")
 
   str_sub(x, -1, -1) <- "K"
-  expect_that(x, equals("ABCDEK"))
+  expect_equal(x, "ABCDEK")
 
   str_sub(x, -2, -1) <- "EFGH"
-  expect_that(x, equals("ABCDEFGH"))
+  expect_equal(x, "ABCDEFGH")
 
   str_sub(x, 2, -2) <- ""
-  expect_that(x, equals("AH"))
+  expect_equal(x, "AH")
 
 
 })
diff --git a/tests/testthat/test-subset.r b/tests/testthat/test-subset.r
new file mode 100644
index 0000000..0e227df
--- /dev/null
+++ b/tests/testthat/test-subset.r
@@ -0,0 +1,10 @@
+context("Subsetting character vectors")
+
+test_that("basic subsetting for fixed patterns works", {
+  expect_equal(str_subset(c("i", "I"), fixed("i")), "i")
+  expect_equal(
+    str_subset(c("i", "I"), fixed("i", ignore_case = TRUE)),
+    c("i", "I")
+  )
+})
+
diff --git a/tests/testthat/test-trim.r b/tests/testthat/test-trim.r
index 3cb7c13..3a50d47 100644
--- a/tests/testthat/test-trim.r
+++ b/tests/testthat/test-trim.r
@@ -1,20 +1,18 @@
 context("Trimming strings")
 
 test_that("trimming removes spaces", {
-  is_trimmed <- equals("abc")
-  expect_that(str_trim("abc   "), is_trimmed)
-  expect_that(str_trim("  abc"), is_trimmed)
-  expect_that(str_trim("  abc   "), is_trimmed)
+  expect_equal(str_trim("abc   "),   "abc")
+  expect_equal(str_trim("   abc"),   "abc")
+  expect_equal(str_trim("  abc   "), "abc")
 })
 
 test_that("trimming removes tabs", {
-  is_trimmed <- equals("abc")
-  expect_that(str_trim("abc\t"), is_trimmed)
-  expect_that(str_trim("\tabc"), is_trimmed)
-  expect_that(str_trim("\tabc\t"), is_trimmed)
+  expect_equal(str_trim("abc\t"),   "abc")
+  expect_equal(str_trim("\tabc"),   "abc")
+  expect_equal(str_trim("\tabc\t"), "abc")
 })
 
 test_that("side argument restricts trimming", {
-  expect_that(str_trim(" abc ", "left"), equals("abc "))
-  expect_that(str_trim(" abc ", "right"), equals(" abc"))
+  expect_equal(str_trim(" abc ", "left"),  "abc ")
+  expect_equal(str_trim(" abc ", "right"), " abc")
 })
diff --git a/tests/testthat/test-word.r b/tests/testthat/test-word.r
new file mode 100644
index 0000000..1ac89a6
--- /dev/null
+++ b/tests/testthat/test-word.r
@@ -0,0 +1,12 @@
+context("Word extraction")
+
+test_that("word extraction", {
+  expect_equal("walk", word("walk the moon"))
+  expect_equal("walk", word("walk the moon", 1))
+  expect_equal("moon", word("walk the moon", 3))
+  expect_equal("the moon", word("walk the moon", 2, 3))
+})
+
+test_that("words past end return NA", {
+  expect_equal(word("a b c", 4), NA_character_)
+})
diff --git a/tests/testthat/test-wrap.r b/tests/testthat/test-wrap.r
new file mode 100644
index 0000000..7fc7987
--- /dev/null
+++ b/tests/testthat/test-wrap.r
@@ -0,0 +1,7 @@
+context("Word-wrapping strings")
+
+test_that("wrapping removes spaces", {
+  expect_equal(str_wrap(""), "")
+  expect_equal(str_wrap(" "), "")
+  expect_equal(str_wrap("  a  "), "a")
+})
diff --git a/vignettes/stringr.Rmd b/vignettes/stringr.Rmd
index 3e79e57..e20db2e 100644
--- a/vignettes/stringr.Rmd
+++ b/vignettes/stringr.Rmd
@@ -58,7 +58,7 @@ There are three string functions that are closely related to their base R equiva
     from the left of the last character. The end position defaults to `-1`, 
     which corresponds to the last character.
 
--   `str_str<-` is equivalent to `substr<-`, but like `str_sub` it understands 
+-   `str_sub<-` is equivalent to `substr<-`, but like `str_sub` it understands 
     negative indices, and replacement strings not do need to be the same length 
     as the string they are replacing.
 
@@ -145,7 +145,7 @@ phone <- "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"
 
 Each pattern matching function has the same first two arguments, a character vector of `string`s to process and a single `pattern` (regular expression) to match. The replace functions have an additional argument specifying the replacement string, and the split functions have an argument to specify the number of pieces.
 
-Unlike base string functions, stringr offers control over matching not through arguments, but through modifier functions, `regexp()`, `coll()` and `fixed()`.  This is a deliberate choice made to simplify these functions. For example, while `grepl` has six arguments, `str_detect()` only has two.
+Unlike base string functions, stringr offers control over matching not through arguments, but through modifier functions, `regex()`, `coll()` and `fixed()`.  This is a deliberate choice made to simplify these functions. For example, while `grepl` has six arguments, `str_detect()` only has two.
 
 ### Regular expressions
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-stringr.git



More information about the debian-med-commit mailing list