[
  {
    "path": ".Rbuildignore",
    "content": "^pkgdown$\n^\\.covrignore$\n^.*\\.Rproj$\n^\\.Rproj\\.user$\n^packrat/\n^\\.Rprofile$\n^\\.travis\\.yml$\n^revdep$\n^cran-comments\\.md$\n^data-raw$\n^codecov\\.yml$\n^\\.httr-oauth$\n^_pkgdown\\.yml$\n^doc$\n^docs$\n^Meta$\n^README\\.Rmd$\n^README-.*\\.png$\n^appveyor\\.yml$\n^CRAN-RELEASE$\n^LICENSE\\.md$\n^\\.github$\n^CRAN-SUBMISSION$\n^[.]?air[.]toml$\n^\\.vscode$\n"
  },
  {
    "path": ".covrignore",
    "content": "R/deprec-*.R\nR/compat-*.R\n"
  },
  {
    "path": ".github/.gitignore",
    "content": "*.html\n"
  },
  {
    "path": ".github/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participation in our\ncommunity a harassment-free experience for everyone, regardless of age, body\nsize, visible or invisible disability, ethnicity, sex characteristics, gender\nidentity and expression, level of experience, education, socio-economic status,\nnationality, personal appearance, race, caste, color, religion, or sexual\nidentity and orientation.\n\nWe pledge to act and interact in ways that contribute to an open, welcoming,\ndiverse, inclusive, and healthy community.\n\n## Our Standards\n\nExamples of behavior that contributes to a positive environment for our\ncommunity include:\n\n* Demonstrating empathy and kindness toward other people\n* Being respectful of differing opinions, viewpoints, and experiences\n* Giving and gracefully accepting constructive feedback\n* Accepting responsibility and apologizing to those affected by our mistakes,\n  and learning from the experience\n* Focusing on what is best not just for us as individuals, but for the overall\n  community\n\nExamples of unacceptable behavior include:\n\n* The use of sexualized language or imagery, and sexual attention or advances of\n  any kind\n* Trolling, insulting or derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or email address,\n  without their explicit permission\n* Other conduct which could reasonably be considered inappropriate in a\n  professional setting\n\n## Enforcement Responsibilities\n\nCommunity leaders are responsible for clarifying and enforcing our standards of\nacceptable behavior and will take appropriate and fair corrective action in\nresponse to any behavior that they deem inappropriate, threatening, offensive,\nor harmful.\n\nCommunity leaders have the right and responsibility to remove, edit, or reject\ncomments, commits, code, wiki edits, issues, and other contributions that are\nnot aligned to this Code of Conduct, and will communicate reasons for moderation\ndecisions when appropriate.\n\n## Scope\n\nThis Code of Conduct applies within all community spaces, and also applies when\nan individual is officially representing the community in public spaces.\nExamples of representing our community include using an official e-mail address,\nposting via an official social media account, or acting as an appointed\nrepresentative at an online or offline event.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported to the community leaders responsible for enforcement at codeofconduct@posit.co. \nAll complaints will be reviewed and investigated promptly and fairly.\n\nAll community leaders are obligated to respect the privacy and security of the\nreporter of any incident.\n\n## Enforcement Guidelines\n\nCommunity leaders will follow these Community Impact Guidelines in determining\nthe consequences for any action they deem in violation of this Code of Conduct:\n\n### 1. Correction\n\n**Community Impact**: Use of inappropriate language or other behavior deemed\nunprofessional or unwelcome in the community.\n\n**Consequence**: A private, written warning from community leaders, providing\nclarity around the nature of the violation and an explanation of why the\nbehavior was inappropriate. A public apology may be requested.\n\n### 2. Warning\n\n**Community Impact**: A violation through a single incident or series of\nactions.\n\n**Consequence**: A warning with consequences for continued behavior. No\ninteraction with the people involved, including unsolicited interaction with\nthose enforcing the Code of Conduct, for a specified period of time. This\nincludes avoiding interactions in community spaces as well as external channels\nlike social media. Violating these terms may lead to a temporary or permanent\nban.\n\n### 3. Temporary Ban\n\n**Community Impact**: A serious violation of community standards, including\nsustained inappropriate behavior.\n\n**Consequence**: A temporary ban from any sort of interaction or public\ncommunication with the community for a specified period of time. No public or\nprivate interaction with the people involved, including unsolicited interaction\nwith those enforcing the Code of Conduct, is allowed during this period.\nViolating these terms may lead to a permanent ban.\n\n### 4. Permanent Ban\n\n**Community Impact**: Demonstrating a pattern of violation of community\nstandards, including sustained inappropriate behavior, harassment of an\nindividual, or aggression toward or disparagement of classes of individuals.\n\n**Consequence**: A permanent ban from any sort of public interaction within the\ncommunity.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 2.1, available at\n<https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.\n\nCommunity Impact Guidelines were inspired by\n[Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion].\n\nFor answers to common questions about this code of conduct, see the FAQ at\n<https://www.contributor-covenant.org/faq>. Translations are available at <https://www.contributor-covenant.org/translations>.\n\n[homepage]: https://www.contributor-covenant.org\n"
  },
  {
    "path": ".github/workflows/R-CMD-check.yaml",
    "content": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help\n#\n# NOTE: This workflow is overkill for most R packages and\n# check-standard.yaml is likely a better choice.\n# usethis::use_github_action(\"check-standard\") will install it.\non:\n  push:\n    branches: [main, master]\n  pull_request:\n    branches: [main, master]\n\nname: R-CMD-check.yaml\n\npermissions: read-all\n\njobs:\n  R-CMD-check:\n    runs-on: ${{ matrix.config.os }}\n\n    name: ${{ matrix.config.os }} (${{ matrix.config.r }})\n\n    strategy:\n      fail-fast: false\n      matrix:\n        config:\n          - {os: macos-latest,   r: 'release'}\n\n          - {os: windows-latest, r: 'release'}\n          # use 4.0 or 4.1 to check with rtools40's older compiler\n          - {os: windows-latest, r: 'oldrel-4'}\n\n          - {os: ubuntu-latest,  r: 'devel', http-user-agent: 'release'}\n          - {os: ubuntu-latest,  r: 'release'}\n          - {os: ubuntu-latest,  r: 'oldrel-1'}\n          - {os: ubuntu-latest,  r: 'oldrel-2'}\n          - {os: ubuntu-latest,  r: 'oldrel-3'}\n          - {os: ubuntu-latest,  r: 'oldrel-4'}\n\n    env:\n      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}\n      R_KEEP_PKG_SOURCE: yes\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: r-lib/actions/setup-pandoc@v2\n\n      - uses: r-lib/actions/setup-r@v2\n        with:\n          r-version: ${{ matrix.config.r }}\n          http-user-agent: ${{ matrix.config.http-user-agent }}\n          use-public-rspm: true\n\n      - uses: r-lib/actions/setup-r-dependencies@v2\n        with:\n          extra-packages: any::rcmdcheck\n          needs: check\n\n      - uses: r-lib/actions/check-r-package@v2\n        with:\n          upload-snapshots: true\n          build_args: 'c(\"--no-manual\",\"--compact-vignettes=gs+qpdf\")'\n"
  },
  {
    "path": ".github/workflows/pkgdown.yaml",
    "content": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help\non:\n  push:\n    branches: [main, master]\n  pull_request:\n    branches: [main, master]\n  release:\n    types: [published]\n  workflow_dispatch:\n\nname: pkgdown.yaml\n\npermissions: read-all\n\njobs:\n  pkgdown:\n    runs-on: ubuntu-latest\n    # Only restrict concurrency for non-PR jobs\n    concurrency:\n      group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }}\n    env:\n      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}\n    permissions:\n      contents: write\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: r-lib/actions/setup-pandoc@v2\n\n      - uses: r-lib/actions/setup-r@v2\n        with:\n          use-public-rspm: true\n\n      - uses: r-lib/actions/setup-r-dependencies@v2\n        with:\n          extra-packages: any::pkgdown, local::.\n          needs: website\n\n      - name: Build site\n        run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE)\n        shell: Rscript {0}\n\n      - name: Deploy to GitHub pages 🚀\n        if: github.event_name != 'pull_request'\n        uses: JamesIves/github-pages-deploy-action@v4.5.0\n        with:\n          clean: false\n          branch: gh-pages\n          folder: docs\n"
  },
  {
    "path": ".github/workflows/pr-commands.yaml",
    "content": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help\non:\n  issue_comment:\n    types: [created]\n\nname: pr-commands.yaml\n\npermissions: read-all\n\njobs:\n  document:\n    if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }}\n    name: document\n    runs-on: ubuntu-latest\n    env:\n      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}\n    permissions:\n      contents: write\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: r-lib/actions/pr-fetch@v2\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: r-lib/actions/setup-r@v2\n        with:\n          use-public-rspm: true\n\n      - uses: r-lib/actions/setup-r-dependencies@v2\n        with:\n          extra-packages: any::roxygen2\n          needs: pr-document\n\n      - name: Document\n        run: roxygen2::roxygenise()\n        shell: Rscript {0}\n\n      - name: commit\n        run: |\n          git config --local user.name \"$GITHUB_ACTOR\"\n          git config --local user.email \"$GITHUB_ACTOR@users.noreply.github.com\"\n          git add man/\\* NAMESPACE\n          git commit -m 'Document'\n\n      - uses: r-lib/actions/pr-push@v2\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n\n  style:\n    if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }}\n    name: style\n    runs-on: ubuntu-latest\n    env:\n      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}\n    permissions:\n      contents: write\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: r-lib/actions/pr-fetch@v2\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n\n      - uses: r-lib/actions/setup-r@v2\n\n      - name: Install dependencies\n        run: install.packages(\"styler\")\n        shell: Rscript {0}\n\n      - name: Style\n        run: styler::style_pkg()\n        shell: Rscript {0}\n\n      - name: commit\n        run: |\n          git config --local user.name \"$GITHUB_ACTOR\"\n          git config --local user.email \"$GITHUB_ACTOR@users.noreply.github.com\"\n          git add \\*.R\n          git commit -m 'Style'\n\n      - uses: r-lib/actions/pr-push@v2\n        with:\n          repo-token: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/test-coverage.yaml",
    "content": "# Workflow derived from https://github.com/r-lib/actions/tree/v2/examples\n# Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help\non:\n  push:\n    branches: [main, master]\n  pull_request:\n    branches: [main, master]\n\nname: test-coverage.yaml\n\npermissions: read-all\n\njobs:\n  test-coverage:\n    runs-on: ubuntu-latest\n    env:\n      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - uses: r-lib/actions/setup-r@v2\n        with:\n          use-public-rspm: true\n\n      - uses: r-lib/actions/setup-r-dependencies@v2\n        with:\n          extra-packages: any::covr, any::xml2\n          needs: coverage\n\n      - name: Test coverage\n        run: |\n          cov <- covr::package_coverage(\n            quiet = FALSE,\n            clean = FALSE,\n            install_path = file.path(normalizePath(Sys.getenv(\"RUNNER_TEMP\"), winslash = \"/\"), \"package\")\n          )\n          covr::to_cobertura(cov)\n        shell: Rscript {0}\n\n      - uses: codecov/codecov-action@v4\n        with:\n          fail_ci_if_error: ${{ github.event_name != 'pull_request' && true || false }}\n          file: ./cobertura.xml\n          plugin: noop\n          disable_search: true\n          token: ${{ secrets.CODECOV_TOKEN }}\n\n      - name: Show testthat output\n        if: always()\n        run: |\n          ## --------------------------------------------------------------------\n          find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \\; || true\n        shell: bash\n\n      - name: Upload test results\n        if: failure()\n        uses: actions/upload-artifact@v4\n        with:\n          name: coverage-test-failures\n          path: ${{ runner.temp }}/package\n"
  },
  {
    "path": ".gitignore",
    "content": "docs\n.Rproj.user\n.Rhistory\n.RData\npackrat/lib*/\npackrat/src\ninst/doc\n.httr-oauth\nrevdep/checks\nrevdep/library\nrevdep/checks.noindex\nrevdep/library.noindex\nrevdep/data.sqlite\n/doc/\n/Meta/\n"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n    \"recommendations\": [\n        \"Posit.air-vscode\"\n    ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n    \"[r]\": {\n        \"editor.formatOnSave\": true,\n        \"editor.defaultFormatter\": \"Posit.air-vscode\"\n    }\n}\n"
  },
  {
    "path": "DESCRIPTION",
    "content": "Package: stringr\nTitle: Simple, Consistent Wrappers for Common String Operations\nVersion: 1.6.0.9000\nAuthors@R: c(\n    person(\"Hadley\", \"Wickham\", , \"hadley@posit.co\", role = c(\"aut\", \"cre\", \"cph\")),\n    person(\"Posit Software, PBC\", role = c(\"cph\", \"fnd\"))\n  )\nDescription: A consistent, simple and easy to use set of wrappers around\n    the fantastic 'stringi' package. All function and argument names (and\n    positions) are consistent, all functions deal with \"NA\"'s and zero\n    length vectors in the same way, and the output from one function is\n    easy to feed into the input of another.\nLicense: MIT + file LICENSE\nURL: https://stringr.tidyverse.org, https://github.com/tidyverse/stringr\nBugReports: https://github.com/tidyverse/stringr/issues\nDepends: \n    R (>= 3.6)\nImports: \n    cli,\n    glue (>= 1.6.1),\n    lifecycle (>= 1.0.3),\n    magrittr,\n    rlang (>= 1.0.0),\n    stringi (>= 1.5.3),\n    vctrs (>= 0.4.0)\nSuggests: \n    covr,\n    dplyr,\n    gt,\n    htmltools,\n    htmlwidgets,\n    knitr,\n    rmarkdown,\n    testthat (>= 3.0.0),\n    tibble\nVignetteBuilder: \n    knitr\nConfig/Needs/website: tidyverse/tidytemplate\nConfig/potools/style: explicit\nConfig/testthat/edition: 3\nEncoding: UTF-8\nLazyData: true\nRoxygen: list(markdown = TRUE)\nRoxygenNote: 7.3.3\n"
  },
  {
    "path": "LICENSE",
    "content": "YEAR: 2023\nCOPYRIGHT HOLDER: stringr authors\n"
  },
  {
    "path": "LICENSE.md",
    "content": "# MIT License\n\nCopyright (c) 2023 stringr authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "NAMESPACE",
    "content": "# Generated by roxygen2: do not edit by hand\n\nS3method(\"[\",stringr_pattern)\nS3method(\"[\",stringr_view)\nS3method(\"[[\",stringr_pattern)\nS3method(print,stringr_view)\nS3method(type,character)\nS3method(type,default)\nS3method(type,stringr_boundary)\nS3method(type,stringr_coll)\nS3method(type,stringr_fixed)\nS3method(type,stringr_regex)\nexport(\"%>%\")\nexport(\"str_sub<-\")\nexport(boundary)\nexport(coll)\nexport(fixed)\nexport(invert_match)\nexport(regex)\nexport(str_c)\nexport(str_conv)\nexport(str_count)\nexport(str_detect)\nexport(str_dup)\nexport(str_ends)\nexport(str_equal)\nexport(str_escape)\nexport(str_extract)\nexport(str_extract_all)\nexport(str_flatten)\nexport(str_flatten_comma)\nexport(str_glue)\nexport(str_glue_data)\nexport(str_ilike)\nexport(str_interp)\nexport(str_length)\nexport(str_like)\nexport(str_locate)\nexport(str_locate_all)\nexport(str_match)\nexport(str_match_all)\nexport(str_order)\nexport(str_pad)\nexport(str_rank)\nexport(str_remove)\nexport(str_remove_all)\nexport(str_replace)\nexport(str_replace_all)\nexport(str_replace_na)\nexport(str_sort)\nexport(str_split)\nexport(str_split_1)\nexport(str_split_fixed)\nexport(str_split_i)\nexport(str_squish)\nexport(str_starts)\nexport(str_sub)\nexport(str_sub_all)\nexport(str_subset)\nexport(str_to_camel)\nexport(str_to_kebab)\nexport(str_to_lower)\nexport(str_to_sentence)\nexport(str_to_snake)\nexport(str_to_title)\nexport(str_to_upper)\nexport(str_trim)\nexport(str_trunc)\nexport(str_unique)\nexport(str_view)\nexport(str_view_all)\nexport(str_which)\nexport(str_width)\nexport(str_wrap)\nexport(word)\nimport(rlang)\nimport(stringi)\nimportFrom(glue,glue)\nimportFrom(lifecycle,deprecated)\nimportFrom(magrittr,\"%>%\")\n"
  },
  {
    "path": "NEWS.md",
    "content": "# stringr (development version)\n\n# stringr 1.6.0\n\n## Breaking changes\n\n* All relevant stringr functions now preserve names (@jonovik, #575).\n* `str_like(ignore_case)` is deprecated, with `str_like()` now always case sensitive to better follow the conventions of the SQL LIKE operator (@edward-burn, #543).\n* In `str_replace_all()`, a `replacement` function now receives all values in a single vector. This radically improves performance at the cost of breaking some existing uses (#462).\n\n## New features\n\n* New `vignette(\"locale-sensitive\")` about locale sensitive functions (@kylieainslie, #404)\n* New `str_ilike()` that follows the conventions of the SQL ILIKE operator (@edward-burn, #543).\n* New `str_to_camel()`, `str_to_snake()`, and `str_to_kebab()` for changing \"programming\" case (@librill, #573 + @arnaudgallou, #593).\n\n## Minor bug fies and improvements\n\n* `str_*` now errors if `pattern` includes any `NA`s (@nash-delcamp-slp, #546).\n* `str_dup()` gains a `sep` argument so you can add a separator between every repeated value (@edward-burn, #564).\n* `str_sub<-` now gives a more informative error if `value` is not the correct length.\n* `str_view()` displays a message when called with a zero-length character vector (@LouisMPenrod, #497).\n* New `[[.stringr_pattern` method to match existing `[.stringr_pattern` (@edward-burn, #569).\n\n# stringr 1.5.2\n\n* `R CMD check` fixes\n\n# stringr 1.5.1\n\n* Some minor documentation improvements.\n\n* `str_trunc()` now correctly truncates strings when `side` is `\"left\"` or\n  `\"center\"` (@UchidaMizuki, #512).\n\n# stringr 1.5.0\n\n## Breaking changes\n\n* stringr functions now consistently implement the tidyverse recycling rules\n  (#372). There are two main changes:\n\n    *  Only vectors of length 1 are recycled. Previously, (e.g.)\n       `str_detect(letters, c(\"x\", \"y\"))` worked, but it now errors.\n\n    *  `str_c()` ignores `NULLs`, rather than treating them as length 0\n        vectors.\n\n    Additionally, many more arguments now throw errors, rather than warnings,\n    if supplied the wrong type of input.\n\n* `regex()` and friends now generate class names with `stringr_` prefix (#384).\n\n* `str_detect()`, `str_starts()`, `str_ends()` and `str_subset()` now error\n  when used with either an empty string (`\"\"`) or a `boundary()`. These\n  operations didn't really make sense (`str_detect(x, \"\")` returned `TRUE`\n  for all non-empty strings) and made it easy to make mistakes when programming.\n\n## New features\n\n* Many tweaks to the documentation to make it more useful and consistent.\n\n* New `vignette(\"from-base\")` by @sastoudt provides a comprehensive comparison\n  between base R functions and their stringr equivalents. It's designed to\n  help you move to stringr if you're already familiar with base R string\n  functions (#266).\n\n* New `str_escape()` escapes regular expression metacharacters, providing\n  an alternative to `fixed()` if you want to compose a pattern from user\n  supplied strings (#408).\n\n* New `str_equal()` compares two character vectors using unicode rules,\n  optionally ignoring case (#381).\n\n* `str_extract()` can now optionally extract a capturing group instead of\n  the complete match (#420).\n\n* New `str_flatten_comma()` is a special case of `str_flatten()` designed for\n  comma separated flattening and can correctly apply the Oxford commas\n  when there are only two elements (#444).\n\n* New `str_split_1()` is tailored for the special case of splitting up a single\n  string (#409).\n\n* New `str_split_i()` extract a single piece from a string (#278, @bfgray3).\n\n* New `str_like()` allows the use of SQL wildcards (#280, @rjpat).\n\n* New `str_rank()` to complete the set of order/rank/sort functions (#353).\n\n* New `str_sub_all()` to extract multiple substrings from each string.\n\n* New `str_unique()` is a wrapper around `stri_unique()` and returns unique\n  string values in a character vector (#249, @seasmith).\n\n* `str_view()` uses ANSI colouring rather than an HTML widget (#370). This\n  works in more places and requires fewer dependencies. It includes a number\n  of other small improvements:\n\n    * It no longer requires a pattern so you can use it to display strings with\n      special characters.\n    * It highlights unusual whitespace characters.\n    * It's vectorised over both string` and `pattern` (#407).\n    * It defaults to displaying all matches, making `str_view_all()` redundant\n      (and hence deprecated) (#455).\n\n* New `str_width()` returns the display width of a string (#380).\n\n* stringr is now licensed as MIT (#351).\n\n## Minor improvements and bug fixes\n\n* Better error message if you supply a non-string pattern (#378).\n\n* A new data source for `sentences` has fixed many small errors.\n\n* `str_extract()` and `str_exctract_all()` now work correctly when `pattern`\n  is a `boundary()`.\n\n* `str_flatten()` gains a `last` argument that optionally override the\n  final separator (#377). It gains a `na.rm` argument to remove missing\n  values (since it's a summary function) (#439).\n\n* `str_pad()` gains `use_width` argument to control whether to use the total\n  code point width or the number of code points as \"width\" of a string (#190).\n\n* `str_replace()` and `str_replace_all()` can use standard tidyverse formula\n  shorthand for `replacement` function (#331).\n\n* `str_starts()` and `str_ends()` now correctly respect regex operator\n  precedence (@carlganz).\n\n* `str_wrap()` breaks only at whitespace by default; set\n  `whitespace_only = FALSE` to return to the previous behaviour (#335, @rjpat).\n\n* `word()` now returns all the sentence when using a negative `start` parameter\n  that is greater or equal than the number of words. (@pdelboca, #245)\n\n# stringr 1.4.1\n\nHot patch release to resolve R CMD check failures.\n\n# stringr 1.4.0\n\n* `str_interp()` now renders lists consistently independent on the presence of\n  additional placeholders (@amhrasmussen).\n\n* New `str_starts()` and `str_ends()` functions to detect patterns at the\n  beginning or end of strings (@jonthegeek, #258).\n\n* `str_subset()`, `str_detect()`, and `str_which()` get `negate` argument,\n  which is useful when you want the elements that do NOT match (#259,\n  @yutannihilation).\n\n* New `str_to_sentence()` function to capitalize with sentence case\n  (@jonthegeek, #202).\n\n# stringr 1.3.1\n\n* `str_replace_all()` with a named vector now respects modifier functions (#207)\n\n* `str_trunc()` is once again vectorised correctly (#203, @austin3dickey).\n\n* `str_view()` handles `NA` values more gracefully (#217). I've also\n  tweaked the sizing policy so hopefully it should work better in notebooks,\n  while preserving the existing behaviour in knit documents (#232).\n\n# stringr 1.3.0\n\n## API changes\n\n* During package build, you may see\n  `Error : object ‘ignore.case’ is not exported by 'namespace:stringr'`.\n  This is because the long deprecated `str_join()`, `ignore.case()` and\n  `perl()` have now been removed.\n\n## New features\n\n* `str_glue()` and `str_glue_data()` provide convenient wrappers around\n  `glue` and `glue_data()` from the [glue](https://glue.tidyverse.org/) package\n  (#157).\n\n* `str_flatten()` is a wrapper around `stri_flatten()` and clearly\n  conveys flattening a character vector into a single string (#186).\n\n* `str_remove()` and `str_remove_all()` functions. These wrap\n  `str_replace()` and `str_replace_all()` to remove patterns from strings.\n  (@Shians, #178)\n\n* `str_squish()` removes spaces from both the left and right side of strings,\n  and also converts multiple space (or space-like characters) to a single\n  space within strings (@stephlocke, #197).\n\n* `str_sub()` gains `omit_na` argument for ignoring `NA`. Accordingly,\n  `str_replace()` now ignores `NA`s and keeps the original strings.\n  (@yutannihilation, #164)\n\n## Bug fixes and minor improvements\n\n* `str_trunc()` now preserves NAs (@ClaytonJY, #162)\n\n* `str_trunc()` now throws an error when `width` is shorter than `ellipsis`\n  (@ClaytonJY, #163).\n\n* Long deprecated `str_join()`, `ignore.case()` and `perl()` have now been\n  removed.\n\n# stringr 1.2.0\n\n## API changes\n\n* `str_match_all()` now returns NA if an optional group doesn't match\n  (previously it returned \"\"). This is more consistent with `str_match()`\n  and other match failures (#134).\n\n## New features\n\n* In `str_replace()`, `replacement` can now be a function that is called once\n  for each match and whose return value is used to replace the match.\n\n* New `str_which()` mimics `grep()` (#129).\n\n* A new vignette (`vignette(\"regular-expressions\")`) describes the\n  details of the regular expressions supported by stringr.\n  The main vignette (`vignette(\"stringr\")`) has been updated to\n  give a high-level overview of the package.\n\n## Minor improvements and bug fixes\n\n* `str_order()` and `str_sort()` gain explicit `numeric` argument for sorting\n  mixed numbers and strings.\n\n* `str_replace_all()` now throws an error if `replacement` is not a character\n  vector. If `replacement` is `NA_character_` it replaces the complete string\n  with replaces with `NA` (#124).\n\n* All functions that take a locale (e.g. `str_to_lower()` and `str_sort()`)\n  default to \"en\" (English) to ensure that the default is consistent across\n  platforms.\n\n# stringr 1.1.0\n\n* Add sample datasets: `fruit`, `words` and `sentences`.\n\n* `fixed()`, `regex()`, and `coll()` now throw an error if you use them with\n  anything other than a plain string (#60). I've clarified that the replacement\n  for `perl()` is `regex()` not `regexp()` (#61). `boundary()` has improved\n  defaults when splitting on non-word boundaries (#58, @lmullen).\n\n* `str_detect()` now can detect boundaries (by checking for a `str_count()` > 0)\n  (#120). `str_subset()` works similarly.\n\n* `str_extract()` and `str_extract_all()` now work with `boundary()`. This is\n  particularly useful if you want to extract logical constructs like words\n  or sentences. `str_extract_all()` respects the `simplify` argument\n  when used with `fixed()` matches.\n\n* `str_subset()` now respects custom options for `fixed()` patterns\n  (#79, @gagolews).\n\n* `str_replace()` and `str_replace_all()` now behave correctly when a\n  replacement string contains `$`s, `\\\\\\\\1`, etc. (#83, #99).\n\n* `str_split()` gains a `simplify` argument to match `str_extract_all()`\n  etc.\n\n* `str_view()` and `str_view_all()` create HTML widgets that display regular\n  expression matches (#96).\n\n* `word()` returns `NA` for indexes greater than number of words (#112).\n\n# stringr 1.0.0\n\n* stringr is now powered by [stringi](https://github.com/gagolews/stringi)\n  instead of base R regular expressions. This improves unicode and support, and\n  makes most operations considerably faster.  If you find stringr inadequate for\n  your string processing needs, I highly recommend looking at stringi in more\n  detail.\n\n* stringr gains a vignette, currently a straight forward update of the article\n  that appeared in the R Journal.\n\n* `str_c()` now returns a zero length vector if any of its inputs are\n  zero length vectors. This is consistent with all other functions, and\n  standard R recycling rules. Similarly, using `str_c(\"x\", NA)` now\n  yields `NA`. If you want `\"xNA\"`, use `str_replace_na()` on the inputs.\n\n* `str_replace_all()` gains a convenient syntax for applying multiple pairs of\n  pattern and replacement to the same vector:\n\n    ```R\n    input <- c(\"abc\", \"def\")\n    str_replace_all(input, c(\"[ad]\" = \"!\", \"[cf]\" = \"?\"))\n    ```\n\n* `str_match()` now returns NA if an optional group doesn't match\n  (previously it returned \"\"). This is more consistent with `str_extract()`\n  and other match failures.\n\n* New `str_subset()` keeps values that match a pattern. It's a convenient\n  wrapper for `x[str_detect(x)]` (#21, @jiho).\n\n* New `str_order()` and `str_sort()` allow you to sort and order strings\n  in a specified locale.\n\n* New `str_conv()` to convert strings from specified encoding to UTF-8.\n\n* New modifier `boundary()` allows you to count, locate and split by\n  character, word, line and sentence boundaries.\n\n* The documentation got a lot of love, and very similar functions (e.g.\n  first and all variants) are now documented together. This should hopefully\n  make it easier to locate the function you need.\n\n* `ignore.case(x)` has been deprecated in favour of\n  `fixed|regex|coll(x, ignore.case = TRUE)`, `perl(x)` has been deprecated in\n  favour of `regex(x)`.\n\n* `str_join()` is deprecated, please use `str_c()` instead.\n\n# stringr 0.6.2\n\n* fixed path in `str_wrap` example so works for more R installations.\n\n* remove dependency on plyr\n\n# stringr 0.6.1\n\n* Zero input to `str_split_fixed` returns 0 row matrix with `n` columns\n\n* Export `str_join`\n\n# stringr 0.6\n\n* new modifier `perl` that switches to Perl regular expressions\n\n* `str_match` now uses new base function `regmatches` to extract matches -\n  this should hopefully be faster than my previous pure R algorithm\n\n# stringr 0.5\n\n* new `str_wrap` function which gives `strwrap` output in a more convenient\n  format\n\n* new `word` function extract words from a string given user defined\n  separator (thanks to suggestion by David Cooper)\n\n* `str_locate` now returns consistent type when matching empty string (thanks\n  to Stavros Macrakis)\n\n* new `str_count` counts number of matches in a string.\n\n* `str_pad` and `str_trim` receive performance tweaks - for large vectors this\n  should give at least a two order of magnitude speed up\n\n* str_length returns NA for invalid multibyte strings\n\n* fix small bug in internal `recyclable` function\n\n# stringr 0.4\n\n * all functions now vectorised with respect to string, pattern (and\n   where appropriate) replacement parameters\n * fixed() function now tells stringr functions to use fixed matching, rather\n   than escaping the regular expression.  Should improve performance for\n   large vectors.\n * new ignore.case() modifier tells stringr functions to ignore case of\n   pattern.\n * str_replace renamed to str_replace_all and new str_replace function added.\n   This makes str_replace consistent with all functions.\n * new str_sub<- function (analogous to substring<-) for substring replacement\n * str_sub now understands negative positions as a position from the end of\n   the string. -1 replaces Inf as indicator for string end.\n * str_pad side argument can be left, right, or both (instead of center)\n * str_trim gains side argument to better match str_pad\n * stringr now has a namespace and imports plyr (rather than requiring it)\n\n# stringr 0.3\n\n * fixed() now also escapes |\n * str_join() renamed to str_c()\n * all functions more carefully check input and return informative error\n   messages if not as expected.\n * add invert_match() function to convert a matrix of location of matches to\n   locations of non-matches\n * add fixed() function to allow matching of fixed strings.\n\n# stringr 0.2\n\n * str_length now returns correct results when used with factors\n * str_sub now correctly replaces Inf in end argument with length of string\n * new function str_split_fixed returns fixed number of splits in a character\n   matrix\n * str_split no longer uses strsplit to preserve trailing breaks\n"
  },
  {
    "path": "R/c.R",
    "content": "#' Join multiple strings into one string\n#'\n#' @description\n#' `str_c()` combines multiple character vectors into a single character\n#' vector. It's very similar to [paste0()] but uses tidyverse recycling and\n#' `NA` rules.\n#'\n#' One way to understand how `str_c()` works is picture a 2d matrix of strings,\n#' where each argument forms a column. `sep` is inserted between each column,\n#' and then each row is combined together into a single string. If `collapse`\n#' is set, it's inserted between each row, and then the result is again\n#' combined, this time into a single string.\n#'\n#' @param ... One or more character vectors.\n#'\n#'   `NULL`s are removed; scalar inputs (vectors of length 1) are recycled to\n#'   the common length of vector inputs.\n#'\n#'   Like most other R functions, missing values are \"infectious\": whenever\n#'   a missing value is combined with another string the result will always\n#'   be missing. Use [dplyr::coalesce()] or [str_replace_na()] to convert to\n#'   the desired value.\n#' @param sep String to insert between input vectors.\n#' @param collapse Optional string used to combine output into single\n#'   string. Generally better to use [str_flatten()] if you needed this\n#'   behaviour.\n#' @return If `collapse = NULL` (the default) a character vector with\n#'   length equal to the longest input. If `collapse` is a string, a character\n#'   vector of length 1.\n#' @export\n#' @examples\n#' str_c(\"Letter: \", letters)\n#' str_c(\"Letter\", letters, sep = \": \")\n#' str_c(letters, \" is for\", \"...\")\n#' str_c(letters[-26], \" comes before \", letters[-1])\n#'\n#' str_c(letters, collapse = \"\")\n#' str_c(letters, collapse = \", \")\n#'\n#' # Differences from paste() ----------------------\n#' # Missing inputs give missing outputs\n#' str_c(c(\"a\", NA, \"b\"), \"-d\")\n#' paste0(c(\"a\", NA, \"b\"), \"-d\")\n#' # Use str_replace_NA to display literal NAs:\n#' str_c(str_replace_na(c(\"a\", NA, \"b\")), \"-d\")\n#'\n#' # Uses tidyverse recycling rules\n#' \\dontrun{str_c(1:2, 1:3)} # errors\n#' paste0(1:2, 1:3)\n#'\n#' str_c(\"x\", character())\n#' paste0(\"x\", character())\nstr_c <- function(..., sep = \"\", collapse = NULL) {\n  check_string(sep)\n  check_string(collapse, allow_null = TRUE)\n\n  dots <- list(...)\n  dots <- dots[!map_lgl(dots, is.null)]\n  vctrs::vec_size_common(!!!dots)\n\n  inject(stri_c(!!!dots, sep = sep, collapse = collapse))\n}\n"
  },
  {
    "path": "R/case.R",
    "content": "#' Convert string to upper case, lower case, title case, or sentence case\n#'\n#' * `str_to_upper()` converts to upper case.\n#' * `str_to_lower()` converts to lower case.\n#' * `str_to_title()` converts to title case, where only the first letter of\n#'   each word is capitalized.\n#' * `str_to_sentence()` convert to sentence case, where only the first letter\n#'   of sentence is capitalized.\n#'\n#' @inheritParams str_detect\n#' @inheritParams coll\n#' @return A character vector the same length as `string`.\n#' @examples\n#' dog <- \"The quick brown dog\"\n#' str_to_upper(dog)\n#' str_to_lower(dog)\n#' str_to_title(dog)\n#' str_to_sentence(\"the quick brown dog\")\n#'\n#' # Locale matters!\n#' str_to_upper(\"i\") # English\n#' str_to_upper(\"i\", \"tr\") # Turkish\n#' @name case\nNULL\n\n#' @export\n#' @rdname case\nstr_to_upper <- function(string, locale = \"en\") {\n  check_string(locale)\n  copy_names(string, stri_trans_toupper(string, locale = locale))\n}\n#' @export\n#' @rdname case\nstr_to_lower <- function(string, locale = \"en\") {\n  check_string(locale)\n  copy_names(string, stri_trans_tolower(string, locale = locale))\n}\n#' @export\n#' @rdname case\nstr_to_title <- function(string, locale = \"en\") {\n  check_string(locale)\n  out <- stri_trans_totitle(\n    string,\n    opts_brkiter = stri_opts_brkiter(locale = locale)\n  )\n  copy_names(string, out)\n}\n#' @export\n#' @rdname case\nstr_to_sentence <- function(string, locale = \"en\") {\n  check_string(locale)\n  out <- stri_trans_totitle(\n    string,\n    opts_brkiter = stri_opts_brkiter(type = \"sentence\", locale = locale)\n  )\n  copy_names(string, out)\n}\n\n\n#' Convert between different types of programming case\n#'\n#' @description\n#' * `str_to_camel()` converts to camel case, where the first letter of\n#'   each word is capitalized, with no separation between words. By default\n#'   the first letter of the first word is not capitalized.\n#'\n#' * `str_to_kebab()` converts to kebab case, where words are converted to\n#'   lower case and separated by dashes (`-`).\n#'\n#' * `str_to_snake()` converts to snake case, where words are converted to\n#'   lower case and separated by underscores (`_`).\n#' @inheritParams str_to_lower\n#' @export\n#' @param first_upper Logical. Should the first letter be capitalized?\n#' @examples\n#' str_to_camel(\"my-variable\")\n#' str_to_camel(\"my-variable\", first_upper = TRUE)\n#'\n#' str_to_snake(\"MyVariable\")\n#' str_to_kebab(\"MyVariable\")\nstr_to_camel <- function(string, first_upper = FALSE) {\n  check_character(string)\n  check_bool(first_upper)\n\n  string <- string |>\n    to_words() |>\n    str_to_title() |>\n    str_remove_all(pattern = fixed(\" \"))\n\n  if (!first_upper) {\n    str_sub(string, 1, 1) <- str_to_lower(str_sub(string, 1, 1))\n  }\n\n  string\n}\n#' @export\n#' @rdname str_to_camel\nstr_to_snake <- function(string) {\n  check_character(string)\n  to_separated_case(string, sep = \"_\")\n}\n#' @export\n#' @rdname str_to_camel\nstr_to_kebab <- function(string) {\n  check_character(string)\n  to_separated_case(string, sep = \"-\")\n}\n\nto_separated_case <- function(string, sep) {\n  out <- to_words(string)\n  str_replace_all(out, fixed(\" \"), sep)\n}\n\nto_words <- function(string) {\n  breakpoints <- paste(\n    # non-word characters\n    \"[^\\\\p{L}\\\\p{N}]+\",\n    # lowercase followed by uppercase\n    \"(?<=\\\\p{Ll})(?=\\\\p{Lu})\",\n    # letter followed by number\n    \"(?<=\\\\p{L})(?=\\\\p{N})\",\n    # number followed by letter\n    \"(?<=\\\\p{N})(?=\\\\p{L})\",\n    # uppercase followed uppercase then lowercase (i.e. end of acronym)\n    \"(?<=\\\\p{Lu})(?=\\\\p{Lu}\\\\p{Ll})\",\n    sep = \"|\"\n  )\n  out <- str_replace_all(string, breakpoints, \" \")\n  out <- str_to_lower(out)\n  str_trim(out)\n}\n"
  },
  {
    "path": "R/compat-obj-type.R",
    "content": "# nocov start --- r-lib/rlang compat-obj-type\n#\n# Changelog\n# =========\n#\n# 2022-10-04:\n# - `obj_type_friendly(value = TRUE)` now shows numeric scalars\n#   literally.\n# - `stop_friendly_type()` now takes `show_value`, passed to\n#   `obj_type_friendly()` as the `value` argument.\n#\n# 2022-10-03:\n# - Added `allow_na` and `allow_null` arguments.\n# - `NULL` is now backticked.\n# - Better friendly type for infinities and `NaN`.\n#\n# 2022-09-16:\n# - Unprefixed usage of rlang functions with `rlang::` to\n#   avoid onLoad issues when called from rlang (#1482).\n#\n# 2022-08-11:\n# - Prefixed usage of rlang functions with `rlang::`.\n#\n# 2022-06-22:\n# - `friendly_type_of()` is now `obj_type_friendly()`.\n# - Added `obj_type_oo()`.\n#\n# 2021-12-20:\n# - Added support for scalar values and empty vectors.\n# - Added `stop_input_type()`\n#\n# 2021-06-30:\n# - Added support for missing arguments.\n#\n# 2021-04-19:\n# - Added support for matrices and arrays (#141).\n# - Added documentation.\n# - Added changelog.\n\n#' Return English-friendly type\n#' @param x Any R object.\n#' @param value Whether to describe the value of `x`. Special values\n#'   like `NA` or `\"\"` are always described.\n#' @param length Whether to mention the length of vectors and lists.\n#' @return A string describing the type. Starts with an indefinite\n#'   article, e.g. \"an integer vector\".\n#' @noRd\nobj_type_friendly <- function(x, value = TRUE) {\n  if (is_missing(x)) {\n    return(\"absent\")\n  }\n\n  if (is.object(x)) {\n    if (inherits(x, \"quosure\")) {\n      type <- \"quosure\"\n    } else {\n      type <- paste(class(x), collapse = \"/\")\n    }\n    return(sprintf(\"a <%s> object\", type))\n  }\n\n  if (!is_vector(x)) {\n    return(.rlang_as_friendly_type(typeof(x)))\n  }\n\n  n_dim <- length(dim(x))\n\n  if (!n_dim) {\n    if (!is_list(x) && length(x) == 1) {\n      if (is_na(x)) {\n        return(switch(\n          typeof(x),\n          logical = \"`NA`\",\n          integer = \"an integer `NA`\",\n          double = if (is.nan(x)) {\n            \"`NaN`\"\n          } else {\n            \"a numeric `NA`\"\n          },\n          complex = \"a complex `NA`\",\n          character = \"a character `NA`\",\n          .rlang_stop_unexpected_typeof(x)\n        ))\n      }\n\n      show_infinites <- function(x) {\n        if (x > 0) {\n          \"`Inf`\"\n        } else {\n          \"`-Inf`\"\n        }\n      }\n      str_encode <- function(x, width = 30, ...) {\n        if (nchar(x) > width) {\n          x <- substr(x, 1, width - 3)\n          x <- paste0(x, \"...\")\n        }\n        encodeString(x, ...)\n      }\n\n      if (value) {\n        if (is.numeric(x) && is.infinite(x)) {\n          return(show_infinites(x))\n        }\n\n        if (is.numeric(x) || is.complex(x)) {\n          number <- as.character(round(x, 2))\n          what <- if (is.complex(x)) \"the complex number\" else \"the number\"\n          return(paste(what, number))\n        }\n\n        return(switch(\n          typeof(x),\n          logical = if (x) \"`TRUE`\" else \"`FALSE`\",\n          character = {\n            what <- if (nzchar(x)) \"the string\" else \"the empty string\"\n            paste(what, str_encode(x, quote = \"\\\"\"))\n          },\n          raw = paste(\"the raw value\", as.character(x)),\n          .rlang_stop_unexpected_typeof(x)\n        ))\n      }\n\n      return(switch(\n        typeof(x),\n        logical = \"a logical value\",\n        integer = \"an integer\",\n        double = if (is.infinite(x)) show_infinites(x) else \"a number\",\n        complex = \"a complex number\",\n        character = if (nzchar(x)) \"a string\" else \"\\\"\\\"\",\n        raw = \"a raw value\",\n        .rlang_stop_unexpected_typeof(x)\n      ))\n    }\n\n    if (length(x) == 0) {\n      return(switch(\n        typeof(x),\n        logical = \"an empty logical vector\",\n        integer = \"an empty integer vector\",\n        double = \"an empty numeric vector\",\n        complex = \"an empty complex vector\",\n        character = \"an empty character vector\",\n        raw = \"an empty raw vector\",\n        list = \"an empty list\",\n        .rlang_stop_unexpected_typeof(x)\n      ))\n    }\n  }\n\n  vec_type_friendly(x)\n}\n\nvec_type_friendly <- function(x, length = FALSE) {\n  if (!is_vector(x)) {\n    abort(\"`x` must be a vector.\")\n  }\n  type <- typeof(x)\n  n_dim <- length(dim(x))\n\n  add_length <- function(type) {\n    if (length && !n_dim) {\n      paste0(type, sprintf(\" of length %s\", length(x)))\n    } else {\n      type\n    }\n  }\n\n  if (type == \"list\") {\n    if (n_dim < 2) {\n      return(add_length(\"a list\"))\n    } else if (is.data.frame(x)) {\n      return(\"a data frame\")\n    } else if (n_dim == 2) {\n      return(\"a list matrix\")\n    } else {\n      return(\"a list array\")\n    }\n  }\n\n  type <- switch(\n    type,\n    logical = \"a logical %s\",\n    integer = \"an integer %s\",\n    numeric = ,\n    double = \"a double %s\",\n    complex = \"a complex %s\",\n    character = \"a character %s\",\n    raw = \"a raw %s\",\n    type = paste0(\"a \", type, \" %s\")\n  )\n\n  if (n_dim < 2) {\n    kind <- \"vector\"\n  } else if (n_dim == 2) {\n    kind <- \"matrix\"\n  } else {\n    kind <- \"array\"\n  }\n  out <- sprintf(type, kind)\n\n  if (n_dim >= 2) {\n    out\n  } else {\n    add_length(out)\n  }\n}\n\n.rlang_as_friendly_type <- function(type) {\n  switch(\n    type,\n\n    list = \"a list\",\n\n    NULL = \"`NULL`\",\n    environment = \"an environment\",\n    externalptr = \"a pointer\",\n    weakref = \"a weak reference\",\n    S4 = \"an S4 object\",\n\n    name = ,\n    symbol = \"a symbol\",\n    language = \"a call\",\n    pairlist = \"a pairlist node\",\n    expression = \"an expression vector\",\n\n    char = \"an internal string\",\n    promise = \"an internal promise\",\n    ... = \"an internal dots object\",\n    any = \"an internal `any` object\",\n    bytecode = \"an internal bytecode object\",\n\n    primitive = ,\n    builtin = ,\n    special = \"a primitive function\",\n    closure = \"a function\",\n\n    type\n  )\n}\n\n.rlang_stop_unexpected_typeof <- function(x, call = caller_env()) {\n  abort(\n    sprintf(\"Unexpected type <%s>.\", typeof(x)),\n    call = call\n  )\n}\n\n#' Return OO type\n#' @param x Any R object.\n#' @return One of `\"bare\"` (for non-OO objects), `\"S3\"`, `\"S4\"`,\n#'   `\"R6\"`, or `\"R7\"`.\n#' @noRd\nobj_type_oo <- function(x) {\n  if (!is.object(x)) {\n    return(\"bare\")\n  }\n\n  class <- inherits(x, c(\"R6\", \"R7_object\"), which = TRUE)\n\n  if (class[[1]]) {\n    \"R6\"\n  } else if (class[[2]]) {\n    \"R7\"\n  } else if (isS4(x)) {\n    \"S4\"\n  } else {\n    \"S3\"\n  }\n}\n\n#' @param x The object type which does not conform to `what`. Its\n#'   `obj_type_friendly()` is taken and mentioned in the error message.\n#' @param what The friendly expected type as a string. Can be a\n#'   character vector of expected types, in which case the error\n#'   message mentions all of them in an \"or\" enumeration.\n#' @param show_value Passed to `value` argument of `obj_type_friendly()`.\n#' @param ... Arguments passed to [abort()].\n#' @inheritParams args_error_context\n#' @noRd\nstop_input_type <- function(\n  x,\n  what,\n  ...,\n  allow_na = FALSE,\n  allow_null = FALSE,\n  show_value = TRUE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  # From compat-cli.R\n  cli <- env_get_list(\n    nms = c(\"format_arg\", \"format_code\"),\n    last = topenv(),\n    default = function(x) sprintf(\"`%s`\", x),\n    inherit = TRUE\n  )\n\n  if (allow_na) {\n    what <- c(what, cli$format_code(\"NA\"))\n  }\n  if (allow_null) {\n    what <- c(what, cli$format_code(\"NULL\"))\n  }\n  if (length(what)) {\n    what <- oxford_comma(what)\n  }\n\n  message <- sprintf(\n    \"%s must be %s, not %s.\",\n    cli$format_arg(arg),\n    what,\n    obj_type_friendly(x, value = show_value)\n  )\n\n  abort(message, ..., call = call, arg = arg)\n}\n\noxford_comma <- function(chr, sep = \", \", final = \"or\") {\n  n <- length(chr)\n\n  if (n < 2) {\n    return(chr)\n  }\n\n  head <- chr[seq_len(n - 1)]\n  last <- chr[n]\n\n  head <- paste(head, collapse = sep)\n\n  # Write a or b. But a, b, or c.\n  if (n > 2) {\n    paste0(head, sep, final, \" \", last)\n  } else {\n    paste0(head, \" \", final, \" \", last)\n  }\n}\n\n# nocov end\n"
  },
  {
    "path": "R/compat-purrr.R",
    "content": "# nocov start - compat-purrr (last updated: rlang 0.3.2.9000)\n\n# This file serves as a reference for compatibility functions for\n# purrr. They are not drop-in replacements but allow a similar style\n# of programming. This is useful in cases where purrr is too heavy a\n# package to depend on. Please find the most recent version in rlang's\n# repository.\n\nmap <- function(.x, .f, ...) {\n  lapply(.x, .f, ...)\n}\nmap_mold <- function(.x, .f, .mold, ...) {\n  out <- vapply(.x, .f, .mold, ..., USE.NAMES = FALSE)\n  names(out) <- names(.x)\n  out\n}\nmap_lgl <- function(.x, .f, ...) {\n  map_mold(.x, .f, logical(1), ...)\n}\nmap_int <- function(.x, .f, ...) {\n  map_mold(.x, .f, integer(1), ...)\n}\nmap_dbl <- function(.x, .f, ...) {\n  map_mold(.x, .f, double(1), ...)\n}\nmap_chr <- function(.x, .f, ...) {\n  map_mold(.x, .f, character(1), ...)\n}\nmap_cpl <- function(.x, .f, ...) {\n  map_mold(.x, .f, complex(1), ...)\n}\n\nwalk <- function(.x, .f, ...) {\n  map(.x, .f, ...)\n  invisible(.x)\n}\n\npluck <- function(.x, .f) {\n  map(.x, `[[`, .f)\n}\npluck_lgl <- function(.x, .f) {\n  map_lgl(.x, `[[`, .f)\n}\npluck_int <- function(.x, .f) {\n  map_int(.x, `[[`, .f)\n}\npluck_dbl <- function(.x, .f) {\n  map_dbl(.x, `[[`, .f)\n}\npluck_chr <- function(.x, .f) {\n  map_chr(.x, `[[`, .f)\n}\npluck_cpl <- function(.x, .f) {\n  map_cpl(.x, `[[`, .f)\n}\n\nmap2 <- function(.x, .y, .f, ...) {\n  out <- mapply(.f, .x, .y, MoreArgs = list(...), SIMPLIFY = FALSE)\n  if (length(out) == length(.x)) {\n    set_names(out, names(.x))\n  } else {\n    set_names(out, NULL)\n  }\n}\nmap2_lgl <- function(.x, .y, .f, ...) {\n  as.vector(map2(.x, .y, .f, ...), \"logical\")\n}\nmap2_int <- function(.x, .y, .f, ...) {\n  as.vector(map2(.x, .y, .f, ...), \"integer\")\n}\nmap2_dbl <- function(.x, .y, .f, ...) {\n  as.vector(map2(.x, .y, .f, ...), \"double\")\n}\nmap2_chr <- function(.x, .y, .f, ...) {\n  as.vector(map2(.x, .y, .f, ...), \"character\")\n}\nmap2_cpl <- function(.x, .y, .f, ...) {\n  as.vector(map2(.x, .y, .f, ...), \"complex\")\n}\n\nargs_recycle <- function(args) {\n  lengths <- map_int(args, length)\n  n <- max(lengths)\n\n  stopifnot(all(lengths == 1L | lengths == n))\n  to_recycle <- lengths == 1L\n  args[to_recycle] <- map(args[to_recycle], function(x) rep.int(x, n))\n\n  args\n}\npmap <- function(.l, .f, ...) {\n  args <- args_recycle(.l)\n  do.call(\n    \"mapply\",\n    c(\n      FUN = list(quote(.f)),\n      args,\n      MoreArgs = quote(list(...)),\n      SIMPLIFY = FALSE,\n      USE.NAMES = FALSE\n    )\n  )\n}\n\nprobe <- function(.x, .p, ...) {\n  if (is_logical(.p)) {\n    stopifnot(length(.p) == length(.x))\n    .p\n  } else {\n    map_lgl(.x, .p, ...)\n  }\n}\n\nkeep <- function(.x, .f, ...) {\n  .x[probe(.x, .f, ...)]\n}\ndiscard <- function(.x, .p, ...) {\n  sel <- probe(.x, .p, ...)\n  .x[is.na(sel) | !sel]\n}\nmap_if <- function(.x, .p, .f, ...) {\n  matches <- probe(.x, .p)\n  .x[matches] <- map(.x[matches], .f, ...)\n  .x\n}\n\ncompact <- function(.x) {\n  Filter(length, .x)\n}\n\ntranspose <- function(.l) {\n  inner_names <- names(.l[[1]])\n  if (is.null(inner_names)) {\n    fields <- seq_along(.l[[1]])\n  } else {\n    fields <- set_names(inner_names)\n  }\n\n  map(fields, function(i) {\n    map(.l, .subset2, i)\n  })\n}\n\nevery <- function(.x, .p, ...) {\n  for (i in seq_along(.x)) {\n    if (!rlang::is_true(.p(.x[[i]], ...))) return(FALSE)\n  }\n  TRUE\n}\nsome <- function(.x, .p, ...) {\n  for (i in seq_along(.x)) {\n    if (rlang::is_true(.p(.x[[i]], ...))) return(TRUE)\n  }\n  FALSE\n}\nnegate <- function(.p) {\n  function(...) !.p(...)\n}\n\nreduce <- function(.x, .f, ..., .init) {\n  f <- function(x, y) .f(x, y, ...)\n  Reduce(f, .x, init = .init)\n}\nreduce_right <- function(.x, .f, ..., .init) {\n  f <- function(x, y) .f(y, x, ...)\n  Reduce(f, .x, init = .init, right = TRUE)\n}\naccumulate <- function(.x, .f, ..., .init) {\n  f <- function(x, y) .f(x, y, ...)\n  Reduce(f, .x, init = .init, accumulate = TRUE)\n}\naccumulate_right <- function(.x, .f, ..., .init) {\n  f <- function(x, y) .f(y, x, ...)\n  Reduce(f, .x, init = .init, right = TRUE, accumulate = TRUE)\n}\n\ndetect <- function(.x, .f, ..., .right = FALSE, .p = is_true) {\n  for (i in index(.x, .right)) {\n    if (.p(.f(.x[[i]], ...))) {\n      return(.x[[i]])\n    }\n  }\n  NULL\n}\ndetect_index <- function(.x, .f, ..., .right = FALSE, .p = is_true) {\n  for (i in index(.x, .right)) {\n    if (.p(.f(.x[[i]], ...))) {\n      return(i)\n    }\n  }\n  0L\n}\nindex <- function(x, right = FALSE) {\n  idx <- seq_along(x)\n  if (right) {\n    idx <- rev(idx)\n  }\n  idx\n}\n\nimap <- function(.x, .f, ...) {\n  map2(.x, vec_index(.x), .f, ...)\n}\nvec_index <- function(x) {\n  names(x) %||% seq_along(x)\n}\n\n# nocov end\n"
  },
  {
    "path": "R/compat-types-check.R",
    "content": "# nocov start --- r-lib/rlang compat-types-check\n#\n# Dependencies\n# ============\n#\n# - compat-obj-type.R\n#\n# Changelog\n# =========\n#\n# 2022-10-04:\n# - Added `check_name()` that forbids the empty string.\n#   `check_string()` allows the empty string by default.\n#\n# 2022-09-28:\n# - Removed `what` arguments.\n# - Added `allow_na` and `allow_null` arguments.\n# - Added `allow_decimal` and `allow_infinite` arguments.\n# - Improved errors with absent arguments.\n#\n#\n# 2022-09-16:\n# - Unprefixed usage of rlang functions with `rlang::` to\n#   avoid onLoad issues when called from rlang (#1482).\n#\n# 2022-08-11:\n# - Added changelog.\n\n# Scalars -----------------------------------------------------------------\n\ncheck_bool <- function(\n  x,\n  ...,\n  allow_na = FALSE,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_bool(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_na && identical(x, NA)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    c(\"`TRUE`\", \"`FALSE`\"),\n    ...,\n    allow_na = allow_na,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_string <- function(\n  x,\n  ...,\n  allow_empty = TRUE,\n  allow_na = FALSE,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    is_string <- .rlang_check_is_string(\n      x,\n      allow_empty = allow_empty,\n      allow_na = allow_na,\n      allow_null = allow_null\n    )\n    if (is_string) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"a single string\",\n    ...,\n    allow_na = allow_na,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\n.rlang_check_is_string <- function(x, allow_empty, allow_na, allow_null) {\n  if (is_string(x)) {\n    if (allow_empty || !is_string(x, \"\")) {\n      return(TRUE)\n    }\n  }\n\n  if (allow_null && is_null(x)) {\n    return(TRUE)\n  }\n\n  if (allow_na && (identical(x, NA) || identical(x, na_chr))) {\n    return(TRUE)\n  }\n\n  FALSE\n}\n\ncheck_name <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    is_string <- .rlang_check_is_string(\n      x,\n      allow_empty = FALSE,\n      allow_na = FALSE,\n      allow_null = allow_null\n    )\n    if (is_string) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"a valid name\",\n    ...,\n    allow_na = FALSE,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_number_decimal <- function(\n  x,\n  ...,\n  min = -Inf,\n  max = Inf,\n  allow_infinite = TRUE,\n  allow_na = FALSE,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  .rlang_types_check_number(\n    x,\n    ...,\n    min = min,\n    max = max,\n    allow_decimal = TRUE,\n    allow_infinite = allow_infinite,\n    allow_na = allow_na,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_number_whole <- function(\n  x,\n  ...,\n  min = -Inf,\n  max = Inf,\n  allow_na = FALSE,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  .rlang_types_check_number(\n    x,\n    ...,\n    min = min,\n    max = max,\n    allow_decimal = FALSE,\n    allow_infinite = FALSE,\n    allow_na = allow_na,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\n.rlang_types_check_number <- function(\n  x,\n  ...,\n  min = -Inf,\n  max = Inf,\n  allow_decimal = FALSE,\n  allow_infinite = FALSE,\n  allow_na = FALSE,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (allow_decimal) {\n    what <- \"a number\"\n  } else {\n    what <- \"a whole number\"\n  }\n\n  .stop <- function(x, what, ...) {\n    stop_input_type(\n      x,\n      what,\n      ...,\n      allow_na = allow_na,\n      allow_null = allow_null,\n      arg = arg,\n      call = call\n    )\n  }\n\n  if (!missing(x)) {\n    is_number <- is_number(\n      x,\n      allow_decimal = allow_decimal,\n      allow_infinite = allow_infinite\n    )\n\n    if (is_number) {\n      if (min > -Inf && max < Inf) {\n        what <- sprintf(\"a number between %s and %s\", min, max)\n      } else {\n        what <- NULL\n      }\n      if (x < min) {\n        what <- what %||% sprintf(\"a number larger than %s\", min)\n        .stop(x, what, ...)\n      }\n      if (x > max) {\n        what <- what %||% sprintf(\"a number smaller than %s\", max)\n        .stop(x, what, ...)\n      }\n      return(invisible(NULL))\n    }\n\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n    if (\n      allow_na &&\n        (identical(x, NA) ||\n          identical(x, na_dbl) ||\n          identical(x, na_int))\n    ) {\n      return(invisible(NULL))\n    }\n  }\n\n  .stop(x, what, ...)\n}\n\nis_number <- function(x, allow_decimal = FALSE, allow_infinite = FALSE) {\n  if (!typeof(x) %in% c(\"integer\", \"double\")) {\n    return(FALSE)\n  }\n  if (length(x) != 1) {\n    return(FALSE)\n  }\n  if (is.na(x)) {\n    return(FALSE)\n  }\n  if (!allow_decimal && !is_integerish(x)) {\n    return(FALSE)\n  }\n  if (!allow_infinite && is.infinite(x)) {\n    return(FALSE)\n  }\n  TRUE\n}\n\ncheck_symbol <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_symbol(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"a symbol\",\n    ...,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_arg <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_symbol(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"an argument name\",\n    ...,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_call <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_call(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"a defused call\",\n    ...,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_environment <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_environment(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"an environment\",\n    ...,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_function <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_function(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"a function\",\n    ...,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_closure <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_closure(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"an R function\",\n    ...,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\ncheck_formula <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_formula(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"a formula\",\n    ...,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\n\n# Vectors -----------------------------------------------------------------\n\ncheck_character <- function(\n  x,\n  ...,\n  allow_null = FALSE,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!missing(x)) {\n    if (is_character(x)) {\n      return(invisible(NULL))\n    }\n    if (allow_null && is_null(x)) {\n      return(invisible(NULL))\n    }\n  }\n\n  stop_input_type(\n    x,\n    \"a character vector\",\n    ...,\n    allow_null = allow_null,\n    arg = arg,\n    call = call\n  )\n}\n\n# nocov end\n"
  },
  {
    "path": "R/conv.R",
    "content": "#' Specify the encoding of a string\n#'\n#' This is a convenient way to override the current encoding of a string.\n#'\n#' @inheritParams str_detect\n#' @param encoding Name of encoding. See [stringi::stri_enc_list()]\n#'   for a complete list.\n#' @export\n#' @examples\n#' # Example from encoding?stringi::stringi\n#' x <- rawToChar(as.raw(177))\n#' x\n#' str_conv(x, \"ISO-8859-2\") # Polish \"a with ogonek\"\n#' str_conv(x, \"ISO-8859-1\") # Plus-minus\nstr_conv <- function(string, encoding) {\n  check_string(encoding)\n\n  copy_names(string, stri_conv(string, encoding, \"UTF-8\"))\n}\n"
  },
  {
    "path": "R/count.R",
    "content": "#' Count number of matches\n#'\n#' Counts the number of times `pattern` is found within each element\n#' of `string.`\n#'\n#' @inheritParams str_detect\n#' @param pattern Pattern to look for.\n#'\n#'   The default interpretation is a regular expression, as described in\n#'   `vignette(\"regular-expressions\")`. Use [regex()] for finer control of the\n#'   matching behaviour.\n#'\n#'   Match a fixed string (i.e. by comparing only bytes), using\n#'   [fixed()]. This is fast, but approximate. Generally,\n#'   for matching human text, you'll want [coll()] which\n#'   respects character matching rules for the specified locale.\n#'\n#'   Match character, word, line and sentence boundaries with\n#'   [boundary()]. The empty string, `\"\"``, is equivalent to\n#'   `boundary(\"character\")`.\n#' @return An integer vector the same length as `string`/`pattern`.\n#' @seealso [stringi::stri_count()] which this function wraps.\n#'\n#'  [str_locate()]/[str_locate_all()] to locate position\n#'  of matches\n#'\n#' @export\n#' @examples\n#' fruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n#' str_count(fruit, \"a\")\n#' str_count(fruit, \"p\")\n#' str_count(fruit, \"e\")\n#' str_count(fruit, c(\"a\", \"b\", \"p\", \"p\"))\n#'\n#' str_count(c(\"a.\", \"...\", \".a.a\"), \".\")\n#' str_count(c(\"a.\", \"...\", \".a.a\"), fixed(\".\"))\nstr_count <- function(string, pattern = \"\") {\n  check_lengths(string, pattern)\n\n  out <- switch(\n    type(pattern),\n    empty = ,\n    bound = stri_count_boundaries(string, opts_brkiter = opts(pattern)),\n    fixed = stri_count_fixed(string, pattern, opts_fixed = opts(pattern)),\n    coll = stri_count_coll(string, pattern, opts_collator = opts(pattern)),\n    regex = stri_count_regex(string, pattern, opts_regex = opts(pattern))\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n"
  },
  {
    "path": "R/data.R",
    "content": "#' Sample character vectors for practicing string manipulations\n#'\n#' `fruit` and `words` come from the `rcorpora` package\n#' written by Gabor Csardi; the data was collected by Darius Kazemi\n#' and made available at \\url{https://github.com/dariusk/corpora}.\n#' `sentences` is a collection of \"Harvard sentences\" used for\n#' standardised testing of voice.\n#'\n#' @format Character vectors.\n#' @name stringr-data\n#' @examples\n#' length(sentences)\n#' sentences[1:5]\n#'\n#' length(fruit)\n#' fruit[1:5]\n#'\n#' length(words)\n#' words[1:5]\nNULL\n\n#' @rdname stringr-data\n#' @format NULL\n\"sentences\"\n\n#' @rdname stringr-data\n#' @format NULL\n\"fruit\"\n\n#' @rdname stringr-data\n#' @format NULL\n\"words\"\n"
  },
  {
    "path": "R/detect.R",
    "content": "#' Detect the presence/absence of a match\n#'\n#' `str_detect()` returns a logical vector with `TRUE` for each element of\n#' `string` that matches `pattern` and `FALSE` otherwise. It's equivalent to\n#' `grepl(pattern, string)`.\n#'\n#' @param string Input vector. Either a character vector, or something\n#'  coercible to one.\n#' @param pattern Pattern to look for.\n#'\n#'   The default interpretation is a regular expression, as described in\n#'   `vignette(\"regular-expressions\")`. Use [regex()] for finer control of the\n#'   matching behaviour.\n#'\n#'   Match a fixed string (i.e. by comparing only bytes), using\n#'   [fixed()]. This is fast, but approximate. Generally,\n#'   for matching human text, you'll want [coll()] which\n#'   respects character matching rules for the specified locale.\n#'\n#'   You can not match boundaries, including `\"\"`, with this function.\n#'\n#' @param negate If `TRUE`, inverts the resulting boolean vector.\n#' @return A logical vector the same length as `string`/`pattern`.\n#' @seealso [stringi::stri_detect()] which this function wraps,\n#'   [str_subset()] for a convenient wrapper around\n#'   `x[str_detect(x, pattern)]`\n#' @export\n#' @examples\n#' fruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n#' str_detect(fruit, \"a\")\n#' str_detect(fruit, \"^a\")\n#' str_detect(fruit, \"a$\")\n#' str_detect(fruit, \"b\")\n#' str_detect(fruit, \"[aeiou]\")\n#'\n#' # Also vectorised over pattern\n#' str_detect(\"aecfg\", letters)\n#'\n#' # Returns TRUE if the pattern do NOT match\n#' str_detect(fruit, \"^p\", negate = TRUE)\nstr_detect <- function(string, pattern, negate = FALSE) {\n  check_lengths(string, pattern)\n  check_bool(negate)\n\n  out <- switch(\n    type(pattern),\n    empty = no_empty(),\n    bound = no_boundary(),\n    fixed = stri_detect_fixed(\n      string,\n      pattern,\n      negate = negate,\n      opts_fixed = opts(pattern)\n    ),\n    coll = stri_detect_coll(\n      string,\n      pattern,\n      negate = negate,\n      opts_collator = opts(pattern)\n    ),\n    regex = stri_detect_regex(\n      string,\n      pattern,\n      negate = negate,\n      opts_regex = opts(pattern)\n    )\n  )\n\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' Detect the presence/absence of a match at the start/end\n#'\n#' `str_starts()` and `str_ends()` are special cases of [str_detect()] that\n#' only match at the beginning or end of a string, respectively.\n#'\n#' @inheritParams str_detect\n#' @param pattern Pattern with which the string starts or ends.\n#'\n#'   The default interpretation is a regular expression, as described in\n#'   [stringi::about_search_regex]. Control options with [regex()].\n#'\n#'   Match a fixed string (i.e. by comparing only bytes), using [fixed()]. This\n#'   is fast, but approximate. Generally, for matching human text, you'll want\n#'   [coll()] which respects character matching rules for the specified locale.\n#'\n#' @return A logical vector.\n#' @export\n#' @examples\n#' fruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n#' str_starts(fruit, \"p\")\n#' str_starts(fruit, \"p\", negate = TRUE)\n#' str_ends(fruit, \"e\")\n#' str_ends(fruit, \"e\", negate = TRUE)\nstr_starts <- function(string, pattern, negate = FALSE) {\n  check_lengths(string, pattern)\n  check_bool(negate)\n\n  out <- switch(\n    type(pattern),\n    empty = no_empty(),\n    bound = no_boundary(),\n    fixed = stri_startswith_fixed(\n      string,\n      pattern,\n      negate = negate,\n      opts_fixed = opts(pattern)\n    ),\n    coll = stri_startswith_coll(\n      string,\n      pattern,\n      negate = negate,\n      opts_collator = opts(pattern)\n    ),\n    regex = {\n      pattern2 <- paste0(\"^(\", pattern, \")\")\n      stri_detect_regex(\n        string,\n        pattern2,\n        negate = negate,\n        opts_regex = opts(pattern)\n      )\n    }\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' @rdname str_starts\n#' @export\nstr_ends <- function(string, pattern, negate = FALSE) {\n  check_lengths(string, pattern)\n  check_bool(negate)\n\n  out <- switch(\n    type(pattern),\n    empty = no_empty(),\n    bound = no_boundary(),\n    fixed = stri_endswith_fixed(\n      string,\n      pattern,\n      negate = negate,\n      opts_fixed = opts(pattern)\n    ),\n    coll = stri_endswith_coll(\n      string,\n      pattern,\n      negate = negate,\n      opts_collator = opts(pattern)\n    ),\n    regex = {\n      pattern2 <- paste0(\"(\", pattern, \")$\")\n      stri_detect_regex(\n        string,\n        pattern2,\n        negate = negate,\n        opts_regex = opts(pattern)\n      )\n    }\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' Detect a pattern in the same way as `SQL`'s `LIKE` and `ILIKE` operators\n#'\n#' @description\n#' `str_like()` and `str_like()` follow the conventions of the SQL `LIKE`\n#' and `ILIKE` operators, namely:\n#'\n#' * Must match the entire string.\n#' * `_` matches a single character (like `.`).\n#' * `%` matches any number of characters (like `.*`).\n#' * `\\%` and `\\_` match literal `%` and `_`.\n#'\n#' The difference between the two functions is their case-sensitivity:\n#' `str_like()` is case sensitive and `str_ilike()` is not.\n#'\n#' @note\n#' Prior to stringr 1.6.0, `str_like()` was incorrectly case-insensitive.\n#'\n#' @inheritParams str_detect\n#' @param pattern A character vector containing a SQL \"like\" pattern.\n#'   See above for details.\n#' @param ignore_case `r lifecycle::badge(\"deprecated\")`\n#' @return A logical vector the same length as `string`.\n#' @export\n#' @examples\n#' fruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n#' str_like(fruit, \"app\")\n#' str_like(fruit, \"app%\")\n#' str_like(fruit, \"APP%\")\n#' str_like(fruit, \"ba_ana\")\n#' str_like(fruit, \"%apple\")\n#'\n#' str_ilike(fruit, \"app\")\n#' str_ilike(fruit, \"app%\")\n#' str_ilike(fruit, \"APP%\")\n#' str_ilike(fruit, \"ba_ana\")\n#' str_ilike(fruit, \"%apple\")\nstr_like <- function(string, pattern, ignore_case = deprecated()) {\n  check_lengths(string, pattern)\n  check_character(pattern)\n  if (inherits(pattern, \"stringr_pattern\")) {\n    cli::cli_abort(\n      \"{.arg pattern} must be a plain string, not a stringr modifier.\"\n    )\n  }\n  if (lifecycle::is_present(ignore_case)) {\n    lifecycle::deprecate_warn(\n      when = \"1.6.0\",\n      what = \"str_like(ignore_case)\",\n      details = c(\n        \"`str_like()` is always case sensitive.\",\n        \"Use `str_ilike()` for case insensitive string matching.\"\n      )\n    )\n    check_bool(ignore_case)\n    if (ignore_case) {\n      return(str_ilike(string, pattern))\n    }\n  }\n\n  pattern <- regex(like_to_regex(pattern), ignore_case = FALSE)\n  out <- stri_detect_regex(string, pattern, opts_regex = opts(pattern))\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' @export\n#' @rdname str_like\nstr_ilike <- function(string, pattern) {\n  check_lengths(string, pattern)\n  check_character(pattern)\n  if (inherits(pattern, \"stringr_pattern\")) {\n    cli::cli_abort(tr_(\n      \"{.arg pattern} must be a plain string, not a stringr modifier.\"\n    ))\n  }\n\n  pattern <- regex(like_to_regex(pattern), ignore_case = TRUE)\n  out <- stri_detect_regex(string, pattern, opts_regex = opts(pattern))\n  preserve_names_if_possible(string, pattern, out)\n}\n\nlike_to_regex <- function(pattern) {\n  converted <- stri_replace_all_regex(\n    pattern,\n    \"(?<!\\\\\\\\|\\\\[)%(?!\\\\])\",\n    \"\\\\.\\\\*\"\n  )\n  converted <- stri_replace_all_regex(converted, \"(?<!\\\\\\\\|\\\\[)_(?!\\\\])\", \"\\\\.\")\n  paste0(\"^\", converted, \"$\")\n}\n"
  },
  {
    "path": "R/dup.R",
    "content": "#' Duplicate a string\n#'\n#' `str_dup()` duplicates the characters within a string, e.g.\n#' `str_dup(\"xy\", 3)` returns `\"xyxyxy\"`.\n#'\n#' @inheritParams str_detect\n#' @param times Number of times to duplicate each string.\n#' @param sep String to insert between each duplicate.\n#' @return A character vector the same length as `string`/`times`.\n#' @export\n#' @examples\n#' fruit <- c(\"apple\", \"pear\", \"banana\")\n#' str_dup(fruit, 2)\n#' str_dup(fruit, 2, sep = \" \")\n#' str_dup(fruit, 1:3)\n#' str_c(\"ba\", str_dup(\"na\", 0:5))\nstr_dup <- function(string, times, sep = NULL) {\n  input <- vctrs::vec_recycle_common(string = string, times = times)\n  check_string(sep, allow_null = TRUE)\n\n  if (is.null(sep)) {\n    out <- stri_dup(input$string, input$times)\n  } else {\n    out <- map_chr(seq_along(input$string), function(i) {\n      paste(rep(string[[i]], input$times[[i]]), collapse = sep)\n    })\n  }\n  names(out) <- names(input$string)\n  out\n}\n"
  },
  {
    "path": "R/equal.R",
    "content": "#' Determine if two strings are equivalent\n#'\n#' This uses Unicode canonicalisation rules, and optionally ignores case.\n#'\n#' @param x,y A pair of character vectors.\n#' @inheritParams str_order\n#' @param ignore_case Ignore case when comparing strings?\n#' @return An logical vector the same length as `x`/`y`.\n#' @seealso [stringi::stri_cmp_equiv()] for the underlying implementation.\n#' @export\n#' @examples\n#' # These two strings encode \"a\" with an accent in two different ways\n#' a1 <- \"\\u00e1\"\n#' a2 <- \"a\\u0301\"\n#' c(a1, a2)\n#'\n#' a1 == a2\n#' str_equal(a1, a2)\n#'\n#' # ohm and omega use different code points but should always be treated\n#' # as equal\n#' ohm <- \"\\u2126\"\n#' omega <- \"\\u03A9\"\n#' c(ohm, omega)\n#'\n#' ohm == omega\n#' str_equal(ohm, omega)\nstr_equal <- function(x, y, locale = \"en\", ignore_case = FALSE, ...) {\n  vctrs::vec_size_common(x = x, y = y)\n  check_string(locale)\n  check_bool(ignore_case)\n\n  opts <- str_opts_collator(\n    locale = locale,\n    ignore_case = ignore_case,\n    ...\n  )\n  stri_cmp_equiv(x, y, opts_collator = opts)\n}\n"
  },
  {
    "path": "R/escape.R",
    "content": "#' Escape regular expression metacharacters\n#'\n#' This function escapes metacharacter, the characters that have special\n#' meaning to the regular expression engine. In most cases you are better\n#' off using [fixed()] since it is faster, but `str_escape()` is useful\n#' if you are composing user provided strings into a pattern.\n#'\n#' @inheritParams str_detect\n#' @return A character vector the same length as `string`.\n#' @export\n#' @examples\n#' str_detect(c(\"a\", \".\"), \".\")\n#' str_detect(c(\"a\", \".\"), str_escape(\".\"))\nstr_escape <- function(string) {\n  out <- str_replace_all(string, \"([.^$\\\\\\\\|*+?{}\\\\[\\\\]()])\", \"\\\\\\\\\\\\1\")\n  copy_names(string, out)\n}\n"
  },
  {
    "path": "R/extract.R",
    "content": "#' Extract the complete match\n#'\n#' `str_extract()` extracts the first complete match from each string,\n#' `str_extract_all()`extracts all matches from each string.\n#'\n#' @inheritParams str_count\n#' @param group If supplied, instead of returning the complete match, will\n#'   return the matched text from the specified capturing group.\n#' @seealso [str_match()] to extract matched groups;\n#'   [stringi::stri_extract()] for the underlying implementation.\n#' @param simplify A boolean.\n#'   * `FALSE` (the default): returns a list of character vectors.\n#'   * `TRUE`: returns a character matrix.\n#' @return\n#' * `str_extract()`: an character vector the same length as `string`/`pattern`.\n#' * `str_extract_all()`: a list of character vectors the same length as\n#'   `string`/`pattern`.\n#' @export\n#' @examples\n#' shopping_list <- c(\"apples x4\", \"bag of flour\", \"bag of sugar\", \"milk x2\")\n#' str_extract(shopping_list, \"\\\\d\")\n#' str_extract(shopping_list, \"[a-z]+\")\n#' str_extract(shopping_list, \"[a-z]{1,4}\")\n#' str_extract(shopping_list, \"\\\\b[a-z]{1,4}\\\\b\")\n#'\n#' str_extract(shopping_list, \"([a-z]+) of ([a-z]+)\")\n#' str_extract(shopping_list, \"([a-z]+) of ([a-z]+)\", group = 1)\n#' str_extract(shopping_list, \"([a-z]+) of ([a-z]+)\", group = 2)\n#'\n#' # Extract all matches\n#' str_extract_all(shopping_list, \"[a-z]+\")\n#' str_extract_all(shopping_list, \"\\\\b[a-z]+\\\\b\")\n#' str_extract_all(shopping_list, \"\\\\d\")\n#'\n#' # Simplify results into character matrix\n#' str_extract_all(shopping_list, \"\\\\b[a-z]+\\\\b\", simplify = TRUE)\n#' str_extract_all(shopping_list, \"\\\\d\", simplify = TRUE)\n#'\n#' # Extract all words\n#' str_extract_all(\"This is, suprisingly, a sentence.\", boundary(\"word\"))\nstr_extract <- function(string, pattern, group = NULL) {\n  if (!is.null(group)) {\n    out <- str_match(string, pattern)[, group + 1]\n    return(preserve_names_if_possible(string, pattern, out))\n  }\n\n  check_lengths(string, pattern)\n  opt <- opts(pattern)\n  out <- switch(\n    type(pattern),\n    empty = stri_extract_first_boundaries(string, opts_brkiter = opt),\n    bound = stri_extract_first_boundaries(string, opts_brkiter = opt),\n    fixed = stri_extract_first_fixed(string, pattern, opts_fixed = opt),\n    coll = stri_extract_first_coll(string, pattern, opts_collator = opt),\n    regex = stri_extract_first_regex(string, pattern, opts_regex = opt)\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' @rdname str_extract\n#' @export\nstr_extract_all <- function(string, pattern, simplify = FALSE) {\n  check_lengths(string, pattern)\n  check_bool(simplify)\n\n  opt <- opts(pattern)\n  out <- switch(\n    type(pattern),\n    empty = stri_extract_all_boundaries(\n      string,\n      simplify = simplify,\n      omit_no_match = TRUE,\n      opts_brkiter = opt\n    ),\n    bound = stri_extract_all_boundaries(\n      string,\n      simplify = simplify,\n      omit_no_match = TRUE,\n      opts_brkiter = opt\n    ),\n    fixed = stri_extract_all_fixed(\n      string,\n      pattern,\n      simplify = simplify,\n      omit_no_match = TRUE,\n      opts_fixed = opt\n    ),\n    coll = stri_extract_all_coll(\n      string,\n      pattern,\n      simplify = simplify,\n      omit_no_match = TRUE,\n      opts_collator = opt\n    ),\n    regex = stri_extract_all_regex(\n      string,\n      pattern,\n      simplify = simplify,\n      omit_no_match = TRUE,\n      opts_regex = opt\n    )\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n"
  },
  {
    "path": "R/flatten.R",
    "content": "#' Flatten a string\n#\n#' @description\n#' `str_flatten()` reduces a character vector to a single string. This is a\n#' summary function because regardless of the length of the input `x`, it\n#' always returns a single string.\n#'\n#' `str_flatten_comma()` is a variation designed specifically for flattening\n#' with commas. It automatically recognises if `last` uses the Oxford comma\n#' and handles the special case of 2 elements.\n#'\n#' @inheritParams str_detect\n#' @param collapse String to insert between each piece. Defaults to `\"\"`.\n#' @param last Optional string to use in place of the final separator.\n#' @param na.rm Remove missing values? If `FALSE` (the default), the result\n#'   will be `NA` if any element of `string` is `NA`.\n#' @return A string, i.e. a character vector of length 1.\n#' @export\n#' @examples\n#' str_flatten(letters)\n#' str_flatten(letters, \"-\")\n#'\n#' str_flatten(letters[1:3], \", \")\n#'\n#' # Use last to customise the last component\n#' str_flatten(letters[1:3], \", \", \" and \")\n#'\n#' # this almost works if you want an Oxford (aka serial) comma\n#' str_flatten(letters[1:3], \", \", \", and \")\n#'\n#' # but it will always add a comma, even when not necessary\n#' str_flatten(letters[1:2], \", \", \", and \")\n#'\n#' # str_flatten_comma knows how to handle the Oxford comma\n#' str_flatten_comma(letters[1:3], \", and \")\n#' str_flatten_comma(letters[1:2], \", and \")\nstr_flatten <- function(string, collapse = \"\", last = NULL, na.rm = FALSE) {\n  check_string(collapse)\n  check_string(last, allow_null = TRUE)\n  check_bool(na.rm)\n\n  if (na.rm) {\n    string <- string[!is.na(string)]\n  }\n\n  n <- length(string)\n  if (!is.null(last) && n >= 2) {\n    string <- c(\n      string[seq2(1, n - 2)],\n      stringi::stri_c(string[[n - 1]], last, string[[n]])\n    )\n  }\n\n  stri_flatten(string, collapse = collapse)\n}\n\n#' @export\n#' @rdname str_flatten\nstr_flatten_comma <- function(string, last = NULL, na.rm = FALSE) {\n  check_string(last, allow_null = TRUE)\n  check_bool(na.rm)\n\n  # Remove comma if exactly two elements, and last uses Oxford comma\n  if (length(string) == 2 && !is.null(last) && str_detect(last, \"^,\")) {\n    last <- str_replace(last, \"^,\", \"\")\n  }\n  str_flatten(string, \", \", last = last, na.rm = na.rm)\n}\n"
  },
  {
    "path": "R/glue.R",
    "content": "#' Interpolation with glue\n#'\n#' @description\n#' These functions are wrappers around [glue::glue()] and [glue::glue_data()],\n#' which provide a powerful and elegant syntax for interpolating strings\n#' with `{}`.\n#'\n#' These wrappers provide a small set of the full options. Use `glue()` and\n#' `glue_data()` directly from glue for more control.\n#'\n#' @inheritParams glue::glue\n#' @return A character vector with same length as the longest input.\n#' @export\n#' @examples\n#' name <- \"Fred\"\n#' age <- 50\n#' anniversary <- as.Date(\"1991-10-12\")\n#' str_glue(\n#'   \"My name is {name}, \",\n#'   \"my age next year is {age + 1}, \",\n#'   \"and my anniversary is {format(anniversary, '%A, %B %d, %Y')}.\"\n#' )\n#'\n#' # single braces can be inserted by doubling them\n#' str_glue(\"My name is {name}, not {{name}}.\")\n#'\n#' # You can also used named arguments\n#' str_glue(\n#'   \"My name is {name}, \",\n#'   \"and my age next year is {age + 1}.\",\n#'   name = \"Joe\",\n#'   age = 40\n#' )\n#'\n#' # `str_glue_data()` is useful in data pipelines\n#' mtcars %>% str_glue_data(\"{rownames(.)} has {hp} hp\")\nstr_glue <- function(..., .sep = \"\", .envir = parent.frame(), .trim = TRUE) {\n  glue::glue(..., .sep = .sep, .envir = .envir, .trim = .trim)\n}\n\n#' @export\n#' @rdname str_glue\nstr_glue_data <- function(\n  .x,\n  ...,\n  .sep = \"\",\n  .envir = parent.frame(),\n  .na = \"NA\"\n) {\n  glue::glue_data(\n    .x,\n    ...,\n    .sep = .sep,\n    .envir = .envir,\n    .na = .na\n  )\n}\n"
  },
  {
    "path": "R/interp.R",
    "content": "#' String interpolation\n#'\n#' @description\n#' `r lifecycle::badge(\"superseded\")`\n#'\n#' `str_interp()` is superseded in favour of [str_glue()].\n#'\n#' String interpolation is a useful way of specifying a character string which\n#' depends on values in a certain environment. It allows for string creation\n#' which is easier to read and write when compared to using e.g.\n#' [paste()] or [sprintf()]. The (template) string can\n#' include expression placeholders of the form `${expression}` or\n#' `$[format]{expression}`, where expressions are valid R expressions that\n#' can be evaluated in the given environment, and `format` is a format\n#' specification valid for use with [sprintf()].\n#'\n#' @param string A template character string. This function is not vectorised:\n#'   a character vector will be collapsed into a single string.\n#' @param env The environment in which to evaluate the expressions.\n#' @seealso [str_glue()] and [str_glue_data()] for alternative approaches to\n#'   the same problem.\n#' @keywords internal\n#' @return An interpolated character string.\n#' @author Stefan Milton Bache\n#' @export\n#' @examples\n#'\n#' # Using values from the environment, and some formats\n#' user_name <- \"smbache\"\n#' amount <- 6.656\n#' account <- 1337\n#' str_interp(\"User ${user_name} (account $[08d]{account}) has $$[.2f]{amount}.\")\n#'\n#' # Nested brace pairs work inside expressions too, and any braces can be\n#' # placed outside the expressions.\n#' str_interp(\"Works with } nested { braces too: $[.2f]{{{2 + 2}*{amount}}}\")\n#'\n#' # Values can also come from a list\n#' str_interp(\n#'   \"One value, ${value1}, and then another, ${value2*2}.\",\n#'   list(value1 = 10, value2 = 20)\n#' )\n#'\n#' # Or a data frame\n#' str_interp(\n#'   \"Values are $[.2f]{max(Sepal.Width)} and $[.2f]{min(Sepal.Width)}.\",\n#'   iris\n#' )\n#'\n#' # Use a vector when the string is long:\n#' max_char <- 80\n#' str_interp(c(\n#'   \"This particular line is so long that it is hard to write \",\n#'   \"without breaking the ${max_char}-char barrier!\"\n#' ))\nstr_interp <- function(string, env = parent.frame()) {\n  check_character(string)\n  string <- str_c(string, collapse = \"\")\n\n  # Find expression placeholders\n  matches <- interp_placeholders(string)\n\n  # Determine if any placeholders were found.\n  if (matches$indices[1] <= 0) {\n    string\n  } else {\n    # Evaluate them to get the replacement strings.\n    replacements <- eval_interp_matches(matches$matches, env)\n\n    # Replace the expressions by their values and return.\n    `regmatches<-`(string, list(matches$indices), FALSE, list(replacements))\n  }\n}\n\n#' Match String Interpolation Placeholders\n#'\n#' Given a character string a set of expression placeholders are matched. They\n#' are of the form \\code{${...}} or optionally \\code{$[f]{...}} where `f`\n#' is a valid format for [sprintf()].\n#'\n#' @param string character: The string to be interpolated.\n#'\n#' @return list containing `indices` (regex match data) and `matches`,\n#'   the string representations of matched expressions.\n#'\n#' @noRd\n#' @author Stefan Milton Bache\ninterp_placeholders <- function(string, error_call = caller_env()) {\n  # Find starting position of ${} or $[]{} placeholders.\n  starts <- gregexpr(\"\\\\$(\\\\[.*?\\\\])?\\\\{\", string)[[1]]\n\n  # Return immediately if no matches are found.\n  if (starts[1] <= 0) {\n    return(list(indices = starts))\n  }\n\n  # Break up the string in parts\n  parts <- substr(\n    rep(string, length(starts)),\n    start = starts,\n    stop = c(starts[-1L] - 1L, nchar(string))\n  )\n\n  # If there are nested placeholders, each part will not contain a full\n  # placeholder in which case we report invalid string interpolation template.\n  if (any(!grepl(\"\\\\$(\\\\[.*?\\\\])?\\\\{.+\\\\}\", parts))) {\n    cli::cli_abort(\n      tr_(\"Invalid template string for interpolation.\"),\n      call = error_call\n    )\n  }\n\n  # For each part, find the opening and closing braces.\n  opens <- lapply(strsplit(parts, \"\"), function(v) which(v == \"{\"))\n  closes <- lapply(strsplit(parts, \"\"), function(v) which(v == \"}\"))\n\n  # Identify the positions within the parts of the matching closing braces.\n  # These are the lengths of the placeholder matches.\n  lengths <- mapply(match_brace, opens, closes)\n\n  # Update the `starts` match data with the\n  attr(starts, \"match.length\") <- lengths\n\n  # Return both the indices (regex match data) and the actual placeholder\n  # matches (as strings.)\n  list(\n    indices = starts,\n    matches = mapply(substr, starts, starts + lengths - 1, x = string)\n  )\n}\n\n#' Evaluate String Interpolation Matches\n#'\n#' The expression part of string interpolation matches are evaluated in a\n#' specified environment and formatted for replacement in the original string.\n#' Used internally by [str_interp()].\n#'\n#' @param matches Match data\n#'\n#' @param env The environment in which to evaluate the expressions.\n#'\n#' @return A character vector of replacement strings.\n#'\n#' @noRd\n#' @author Stefan Milton Bache\neval_interp_matches <- function(matches, env, error_call = caller_env()) {\n  # Extract expressions from the matches\n  expressions <- extract_expressions(matches, error_call = error_call)\n\n  # Evaluate them in the given environment\n  values <- lapply(\n    expressions,\n    eval,\n    envir = env,\n    enclos = if (is.environment(env)) env else environment(env)\n  )\n\n  # Find the formats to be used\n  formats <- extract_formats(matches)\n\n  # Format the values and return.\n  mapply(sprintf, formats, values, SIMPLIFY = FALSE)\n}\n\n#' Extract Expression Objects from String Interpolation Matches\n#'\n#' An interpolation match object will contain both its wrapping \\code{${ }} part\n#' and possibly a format. This extracts the expression parts and parses them to\n#' prepare them for evaluation.\n#'\n#' @param matches Match data\n#'\n#' @return list of R expressions\n#'\n#' @noRd\n#' @author Stefan Milton Bache\nextract_expressions <- function(matches, error_call = caller_env()) {\n  # Parse function for text argument as first argument.\n\n  parse_text <- function(text) {\n    withCallingHandlers(\n      parse(text = text),\n      error = function(e) {\n        cli::cli_abort(\n          tr_(\"Failed to parse input {.str {text}}\"),\n          parent = e,\n          call = error_call\n        )\n      }\n    )\n  }\n\n  # string representation of the expressions (without the possible formats).\n  strings <- gsub(\"\\\\$(\\\\[.+?\\\\])?\\\\{\", \"\", matches)\n\n  # Remove the trailing closing brace and parse.\n  lapply(substr(strings, 1L, nchar(strings) - 1), parse_text)\n}\n\n\n#' Extract String Interpolation Formats from Matched Placeholders\n#'\n#' An expression placeholder for string interpolation may optionally contain a\n#' format valid for [sprintf()]. This function will extract such or\n#' default to \"s\" the format for strings.\n#'\n#' @param matches Match data\n#'\n#' @return A character vector of format specifiers.\n#'\n#' @noRd\n#' @author Stefan Milton Bache\nextract_formats <- function(matches) {\n  # Extract the optional format parts.\n  formats <- gsub(\"\\\\$(\\\\[(.+?)\\\\])?.*\", \"\\\\2\", matches)\n\n  # Use string options \"s\" as default when not specified.\n  paste0(\"%\", ifelse(formats == \"\", \"s\", formats))\n}\n\n#' Utility Function for Matching a Closing Brace\n#'\n#' Given positions of opening and closing braces `match_brace` identifies\n#' the closing brace matching the first opening brace.\n#'\n#' @param opening integer: Vector with positions of opening braces.\n#'\n#' @param closing integer: Vector with positions of closing braces.\n#'\n#' @return Integer with the posision of the matching brace.\n#'\n#' @noRd\n#' @author Stefan Milton Bache\nmatch_brace <- function(opening, closing) {\n  # maximum index for the matching closing brace\n  max_close <- max(closing)\n\n  # \"path\" for mapping opening and closing breaces\n  path <- numeric(max_close)\n\n  # Set openings to 1, and closings to -1\n  path[opening[opening < max_close]] <- 1\n  path[closing] <- -1\n\n  # Cumulate the path ...\n  cumpath <- cumsum(path)\n\n  # ... and the first 0 after the first opening identifies the match.\n  min(which(1:max_close > min(which(cumpath == 1)) & cumpath == 0))\n}\n"
  },
  {
    "path": "R/length.R",
    "content": "#' Compute the length/width\n#'\n#' @description\n#' `str_length()` returns the number of codepoints in a string. These are\n#' the individual elements (which are often, but not always letters) that\n#' can be extracted with [str_sub()].\n#'\n#' `str_width()` returns how much space the string will occupy when printed\n#' in a fixed width font (i.e. when printed in the console).\n#'\n#' @inheritParams str_detect\n#' @return A numeric vector the same length as `string`.\n#' @seealso [stringi::stri_length()] which this function wraps.\n#' @export\n#' @examples\n#' str_length(letters)\n#' str_length(NA)\n#' str_length(factor(\"abc\"))\n#' str_length(c(\"i\", \"like\", \"programming\", NA))\n#'\n#' # Some characters, like emoji and Chinese characters (hanzi), are square\n#' # which means they take up the width of two Latin characters\n#' x <- c(\"\\u6c49\\u5b57\", \"\\U0001f60a\")\n#' str_view(x)\n#' str_width(x)\n#' str_length(x)\n#'\n#' # There are two ways of representing a u with an umlaut\n#' u <- c(\"\\u00fc\", \"u\\u0308\")\n#' # They have the same width\n#' str_width(u)\n#' # But a different length\n#' str_length(u)\n#' # Because the second element is made up of a u + an accent\n#' str_sub(u, 1, 1)\nstr_length <- function(string) {\n  copy_names(string, stri_length(string))\n}\n\n#' @export\n#' @rdname str_length\nstr_width <- function(string) {\n  copy_names(string, stri_width(string))\n}\n"
  },
  {
    "path": "R/locate.R",
    "content": "#' Find location of match\n#'\n#' @description\n#' `str_locate()` returns the `start` and `end` position of the first match;\n#' `str_locate_all()` returns the `start` and `end` position of each match.\n#'\n#' Because the `start` and `end` values are inclusive, zero-length matches\n#' (e.g. `$`, `^`, `\\\\b`) will have an `end` that is smaller than `start`.\n#'\n#' @inheritParams str_count\n#' @returns\n#' * `str_locate()` returns an integer matrix with two columns and\n#'   one row for each element of `string`. The first column, `start`,\n#'   gives the position at the start of the match, and the second column, `end`,\n#'   gives the position of the end.\n#'\n#'* `str_locate_all()` returns a list of integer matrices with the same\n#'   length as `string`/`pattern`. The matrices have columns `start` and `end`\n#'   as above, and one row for each match.\n#' @seealso\n#'   [str_extract()] for a convenient way of extracting matches,\n#'   [stringi::stri_locate()] for the underlying implementation.\n#' @export\n#' @examples\n#' fruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n#' str_locate(fruit, \"$\")\n#' str_locate(fruit, \"a\")\n#' str_locate(fruit, \"e\")\n#' str_locate(fruit, c(\"a\", \"b\", \"p\", \"p\"))\n#'\n#' str_locate_all(fruit, \"a\")\n#' str_locate_all(fruit, \"e\")\n#' str_locate_all(fruit, c(\"a\", \"b\", \"p\", \"p\"))\n#'\n#' # Find location of every character\n#' str_locate_all(fruit, \"\")\nstr_locate <- function(string, pattern) {\n  check_lengths(string, pattern)\n\n  out <- switch(\n    type(pattern),\n    empty = ,\n    bound = stri_locate_first_boundaries(string, opts_brkiter = opts(pattern)),\n    fixed = stri_locate_first_fixed(\n      string,\n      pattern,\n      opts_fixed = opts(pattern)\n    ),\n    coll = stri_locate_first_coll(\n      string,\n      pattern,\n      opts_collator = opts(pattern)\n    ),\n    regex = stri_locate_first_regex(string, pattern, opts_regex = opts(pattern))\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' @rdname str_locate\n#' @export\nstr_locate_all <- function(string, pattern) {\n  check_lengths(string, pattern)\n  opts <- opts(pattern)\n\n  out <- switch(\n    type(pattern),\n    empty = ,\n    bound = stri_locate_all_boundaries(\n      string,\n      omit_no_match = TRUE,\n      opts_brkiter = opts\n    ),\n    fixed = stri_locate_all_fixed(\n      string,\n      pattern,\n      omit_no_match = TRUE,\n      opts_fixed = opts\n    ),\n    regex = stri_locate_all_regex(\n      string,\n      pattern,\n      omit_no_match = TRUE,\n      opts_regex = opts\n    ),\n    coll = stri_locate_all_coll(\n      string,\n      pattern,\n      omit_no_match = TRUE,\n      opts_collator = opts\n    )\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n\n\n#' Switch location of matches to location of non-matches\n#'\n#' Invert a matrix of match locations to match the opposite of what was\n#' previously matched.\n#'\n#' @param loc matrix of match locations, as from [str_locate_all()]\n#' @return numeric match giving locations of non-matches\n#' @export\n#' @examples\n#' numbers <- \"1 and 2 and 4 and 456\"\n#' num_loc <- str_locate_all(numbers, \"[0-9]+\")[[1]]\n#' str_sub(numbers, num_loc[, \"start\"], num_loc[, \"end\"])\n#'\n#' text_loc <- invert_match(num_loc)\n#' str_sub(numbers, text_loc[, \"start\"], text_loc[, \"end\"])\ninvert_match <- function(loc) {\n  cbind(\n    start = c(0L, loc[, \"end\"] + 1L),\n    end = c(loc[, \"start\"] - 1L, -1L)\n  )\n}\n"
  },
  {
    "path": "R/match.R",
    "content": "#' Extract components (capturing groups) from a match\n#'\n#' @description\n#' Extract any number of matches defined by unnamed, `(pattern)`, and\n#' named, `(?<name>pattern)` capture groups.\n#'\n#' Use a non-capturing group, `(?:pattern)`, if you need to override default\n#' operate precedence but don't want to capture the result.\n#'\n#' @inheritParams str_detect\n#' @param pattern Unlike other stringr functions, `str_match()` only supports\n#'   regular expressions, as described `vignette(\"regular-expressions\")`.\n#'   The pattern should contain at least one capturing group.\n#' @return\n#' * `str_match()`: a character matrix with the same number of rows as the\n#'   length of `string`/`pattern`. The first column is the complete match,\n#'   followed by one column for each capture group. The columns will be named\n#'   if you used \"named captured groups\", i.e. `(?<name>pattern')`.\n#'\n#' * `str_match_all()`: a list of the same length as `string`/`pattern`\n#'   containing character matrices. Each matrix has columns as described above\n#'   and one row for each match.\n#'\n#' @seealso [str_extract()] to extract the complete match,\n#'   [stringi::stri_match()] for the underlying implementation.\n#' @export\n#' @examples\n#' strings <- c(\" 219 733 8965\", \"329-293-8753 \", \"banana\", \"595 794 7569\",\n#'   \"387 287 6718\", \"apple\", \"233.398.9187  \", \"482 952 3315\",\n#'   \"239 923 8115 and 842 566 4692\", \"Work: 579-499-7527\", \"$1000\",\n#'   \"Home: 543.355.3679\")\n#' phone <- \"([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})\"\n#'\n#' str_extract(strings, phone)\n#' str_match(strings, phone)\n#'\n#' # Extract/match all\n#' str_extract_all(strings, phone)\n#' str_match_all(strings, phone)\n#'\n#' # You can also name the groups to make further manipulation easier\n#' phone <- \"(?<area>[2-9][0-9]{2})[- .](?<phone>[0-9]{3}[- .][0-9]{4})\"\n#' str_match(strings, phone)\n#'\n#' x <- c(\"<a> <b>\", \"<a> <>\", \"<a>\", \"\", NA)\n#' str_match(x, \"<(.*?)> <(.*?)>\")\n#' str_match_all(x, \"<(.*?)>\")\n#'\n#' str_extract(x, \"<.*?>\")\n#' str_extract_all(x, \"<.*?>\")\nstr_match <- function(string, pattern) {\n  check_lengths(string, pattern)\n  if (type(pattern) != \"regex\") {\n    cli::cli_abort(tr_(\"{.arg pattern} must be a regular expression.\"))\n  }\n\n  out <- stri_match_first_regex(string, pattern, opts_regex = opts(pattern))\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' @rdname str_match\n#' @export\nstr_match_all <- function(string, pattern) {\n  check_lengths(string, pattern)\n  if (type(pattern) != \"regex\") {\n    cli::cli_abort(tr_(\"{.arg pattern} must be a regular expression.\"))\n  }\n\n  out <- stri_match_all_regex(\n    string,\n    pattern,\n    omit_no_match = TRUE,\n    opts_regex = opts(pattern)\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n"
  },
  {
    "path": "R/modifiers.R",
    "content": "#' Control matching behaviour with modifier functions\n#'\n#' @description\n#' Modifier functions control the meaning of the `pattern` argument to\n#' stringr functions:\n#'\n#' * `boundary()`: Match boundaries between things.\n#' * `coll()`: Compare strings using standard Unicode collation rules.\n#' * `fixed()`: Compare literal bytes.\n#' * `regex()` (the default): Uses ICU regular expressions.\n#'\n#' @param pattern Pattern to modify behaviour.\n#' @param ignore_case Should case differences be ignored in the match?\n#'   For `fixed()`, this uses a simple algorithm which assumes a\n#'   one-to-one mapping between upper and lower case letters.\n#' @return A stringr modifier object, i.e. a character vector with\n#'   parent S3 class `stringr_pattern`.\n#' @name modifiers\n#' @examples\n#' pattern <- \"a.b\"\n#' strings <- c(\"abb\", \"a.b\")\n#' str_detect(strings, pattern)\n#' str_detect(strings, fixed(pattern))\n#' str_detect(strings, coll(pattern))\n#'\n#' # coll() is useful for locale-aware case-insensitive matching\n#' i <- c(\"I\", \"\\u0130\", \"i\")\n#' i\n#' str_detect(i, fixed(\"i\", TRUE))\n#' str_detect(i, coll(\"i\", TRUE))\n#' str_detect(i, coll(\"i\", TRUE, locale = \"tr\"))\n#'\n#' # Word boundaries\n#' words <- c(\"These are   some words.\")\n#' str_count(words, boundary(\"word\"))\n#' str_split(words, \" \")[[1]]\n#' str_split(words, boundary(\"word\"))[[1]]\n#'\n#' # Regular expression variations\n#' str_extract_all(\"The Cat in the Hat\", \"[a-z]+\")\n#' str_extract_all(\"The Cat in the Hat\", regex(\"[a-z]+\", TRUE))\n#'\n#' str_extract_all(\"a\\nb\\nc\", \"^.\")\n#' str_extract_all(\"a\\nb\\nc\", regex(\"^.\", multiline = TRUE))\n#'\n#' str_extract_all(\"a\\nb\\nc\", \"a.\")\n#' str_extract_all(\"a\\nb\\nc\", regex(\"a.\", dotall = TRUE))\nNULL\n\n#' @export\n#' @rdname modifiers\nfixed <- function(pattern, ignore_case = FALSE) {\n  pattern <- as_bare_character(pattern)\n  check_bool(ignore_case)\n\n  options <- stri_opts_fixed(case_insensitive = ignore_case)\n\n  structure(\n    pattern,\n    options = options,\n    class = c(\"stringr_fixed\", \"stringr_pattern\", \"character\")\n  )\n}\n\n#' @export\n#' @rdname modifiers\n#' @param locale Locale to use for comparisons. See\n#'   [stringi::stri_locale_list()] for all possible options.\n#'   Defaults to \"en\" (English) to ensure that default behaviour is\n#'   consistent across platforms.\n#' @param ... Other less frequently used arguments passed on to\n#'   [stringi::stri_opts_collator()],\n#'   [stringi::stri_opts_regex()], or\n#'   [stringi::stri_opts_brkiter()]\ncoll <- function(pattern, ignore_case = FALSE, locale = \"en\", ...) {\n  pattern <- as_bare_character(pattern)\n  check_bool(ignore_case)\n  check_string(locale)\n\n  options <- str_opts_collator(\n    ignore_case = ignore_case,\n    locale = locale,\n    ...\n  )\n\n  structure(\n    pattern,\n    options = options,\n    class = c(\"stringr_coll\", \"stringr_pattern\", \"character\")\n  )\n}\n\n\nstr_opts_collator <- function(\n  locale = \"en\",\n  ignore_case = FALSE,\n  strength = NULL,\n  ...\n) {\n  strength <- strength %||% if (ignore_case) 2L else 3L\n  stri_opts_collator(\n    strength = strength,\n    locale = locale,\n    ...\n  )\n}\n\n# used for testing\nturkish_I <- function() {\n  coll(\"I\", ignore_case = TRUE, locale = \"tr\")\n}\n\n#' @export\n#' @rdname modifiers\n#' @param multiline If `TRUE`, `$` and `^` match\n#'   the beginning and end of each line. If `FALSE`, the\n#'   default, only match the start and end of the input.\n#' @param comments If `TRUE`, white space and comments beginning with\n#'   `#` are ignored. Escape literal spaces with `\\\\ `.\n#' @param dotall If `TRUE`, `.` will also match line terminators.\nregex <- function(\n  pattern,\n  ignore_case = FALSE,\n  multiline = FALSE,\n  comments = FALSE,\n  dotall = FALSE,\n  ...\n) {\n  pattern <- as_bare_character(pattern)\n  check_bool(ignore_case)\n  check_bool(multiline)\n  check_bool(comments)\n  check_bool(dotall)\n\n  options <- stri_opts_regex(\n    case_insensitive = ignore_case,\n    multiline = multiline,\n    comments = comments,\n    dotall = dotall,\n    ...\n  )\n\n  structure(\n    pattern,\n    options = options,\n    class = c(\"stringr_regex\", \"stringr_pattern\", \"character\")\n  )\n}\n\n#' @param type Boundary type to detect.\n#' \\describe{\n#'  \\item{`character`}{Every character is a boundary.}\n#'  \\item{`line_break`}{Boundaries are places where it is acceptable to have\n#'    a line break in the current locale.}\n#'  \\item{`sentence`}{The beginnings and ends of sentences are boundaries,\n#'    using intelligent rules to avoid counting abbreviations\n#'    ([details](https://www.unicode.org/reports/tr29/#Sentence_Boundaries)).}\n#'  \\item{`word`}{The beginnings and ends of words are boundaries.}\n#' }\n#' @param skip_word_none Ignore \"words\" that don't contain any characters\n#'   or numbers - i.e. punctuation. Default `NA` will skip such \"words\"\n#'   only when splitting on `word` boundaries.\n#' @export\n#' @rdname modifiers\nboundary <- function(\n  type = c(\"character\", \"line_break\", \"sentence\", \"word\"),\n  skip_word_none = NA,\n  ...\n) {\n  type <- arg_match(type)\n  check_bool(skip_word_none, allow_na = TRUE)\n\n  if (identical(skip_word_none, NA)) {\n    skip_word_none <- type == \"word\"\n  }\n\n  options <- stri_opts_brkiter(\n    type = type,\n    skip_word_none = skip_word_none,\n    ...\n  )\n\n  structure(\n    NA_character_,\n    options = options,\n    class = c(\"stringr_boundary\", \"stringr_pattern\", \"character\")\n  )\n}\n\nopts <- function(x) {\n  if (identical(x, \"\")) {\n    stri_opts_brkiter(type = \"character\")\n  } else {\n    attr(x, \"options\")\n  }\n}\n\ntype <- function(x, error_call = caller_env()) {\n  UseMethod(\"type\")\n}\n#' @export\ntype.stringr_boundary <- function(x, error_call = caller_env()) {\n  \"bound\"\n}\n#' @export\ntype.stringr_regex <- function(x, error_call = caller_env()) {\n  \"regex\"\n}\n#' @export\ntype.stringr_coll <- function(x, error_call = caller_env()) {\n  \"coll\"\n}\n#' @export\ntype.stringr_fixed <- function(x, error_call = caller_env()) {\n  \"fixed\"\n}\n#' @export\ntype.character <- function(x, error_call = caller_env()) {\n  if (any(is.na(x))) {\n    cli::cli_abort(\n      tr_(\"{.arg pattern} can not contain NAs.\"),\n      call = error_call\n    )\n  }\n\n  if (identical(x, \"\")) \"empty\" else \"regex\"\n}\n\n#' @export\ntype.default <- function(x, error_call = caller_env()) {\n  if (inherits(x, \"regex\")) {\n    # Fallback for rex\n    return(\"regex\")\n  }\n\n  cli::cli_abort(\n    tr_(\n      \"{.arg pattern} must be a character vector, not {.obj_type_friendly {x}}.\"\n    ),\n    call = error_call\n  )\n}\n\n#' @export\n`[.stringr_pattern` <- function(x, i) {\n  structure(\n    NextMethod(),\n    options = attr(x, \"options\"),\n    class = class(x)\n  )\n}\n\n#' @export\n`[[.stringr_pattern` <- function(x, i) {\n  structure(\n    NextMethod(),\n    options = attr(x, \"options\"),\n    class = class(x)\n  )\n}\n\nas_bare_character <- function(x, call = caller_env()) {\n  if (is.character(x) && !is.object(x)) {\n    # All OK!\n    return(x)\n  }\n\n  warn(\"Coercing `pattern` to a plain character vector.\", call = call)\n  as.character(x)\n}\n"
  },
  {
    "path": "R/pad.R",
    "content": "#' Pad a string to minimum width\n#'\n#' Pad a string to a fixed width, so that\n#' `str_length(str_pad(x, n))` is always greater than or equal to `n`.\n#'\n#' @inheritParams str_detect\n#' @param width Minimum width of padded strings.\n#' @param side Side on which padding character is added (left, right or both).\n#' @param pad Single padding character (default is a space).\n#' @param use_width If `FALSE`, use the length of the string instead of the\n#'   width; see [str_width()]/[str_length()] for the difference.\n#' @return A character vector the same length as `stringr`/`width`/`pad`.\n#' @seealso [str_trim()] to remove whitespace;\n#'   [str_trunc()] to decrease the maximum width of a string.\n#' @export\n#' @examples\n#' rbind(\n#'   str_pad(\"hadley\", 30, \"left\"),\n#'   str_pad(\"hadley\", 30, \"right\"),\n#'   str_pad(\"hadley\", 30, \"both\")\n#' )\n#'\n#' # All arguments are vectorised except side\n#' str_pad(c(\"a\", \"abc\", \"abcdef\"), 10)\n#' str_pad(\"a\", c(5, 10, 20))\n#' str_pad(\"a\", 10, pad = c(\"-\", \"_\", \" \"))\n#'\n#' # Longer strings are returned unchanged\n#' str_pad(\"hadley\", 3)\nstr_pad <- function(\n  string,\n  width,\n  side = c(\"left\", \"right\", \"both\"),\n  pad = \" \",\n  use_width = TRUE\n) {\n  vctrs::vec_size_common(string = string, width = width, pad = pad)\n  side <- arg_match(side)\n  check_bool(use_width)\n\n  out <- switch(\n    side,\n    left = stri_pad_left(string, width, pad = pad, use_length = !use_width),\n    right = stri_pad_right(string, width, pad = pad, use_length = !use_width),\n    both = stri_pad_both(string, width, pad = pad, use_length = !use_width)\n  )\n  # Preserve names unless `string` is recycled\n  if (length(out) == length(string)) copy_names(string, out) else out\n}\n"
  },
  {
    "path": "R/remove.R",
    "content": "#' Remove matched patterns\n#'\n#' Remove matches, i.e. replace them with `\"\"`.\n#'\n#' @inheritParams str_detect\n#' @return A character vector the same length as `string`/`pattern`.\n#' @seealso [str_replace()] for the underlying implementation.\n#' @export\n#' @examples\n#' fruits <- c(\"one apple\", \"two pears\", \"three bananas\")\n#' str_remove(fruits, \"[aeiou]\")\n#' str_remove_all(fruits, \"[aeiou]\")\nstr_remove <- function(string, pattern) {\n  str_replace(string, pattern, \"\")\n}\n\n#' @export\n#' @rdname str_remove\nstr_remove_all <- function(string, pattern) {\n  str_replace_all(string, pattern, \"\")\n}\n"
  },
  {
    "path": "R/replace.R",
    "content": "#' Replace matches with new text\n#'\n#' `str_replace()` replaces the first match; `str_replace_all()` replaces\n#' all matches.\n#'\n#' @inheritParams str_detect\n#' @param pattern Pattern to look for.\n#'\n#'   The default interpretation is a regular expression, as described\n#'   in [stringi::about_search_regex]. Control options with\n#'   [regex()].\n#'\n#'   For `str_replace_all()` this can also be a named vector\n#'   (`c(pattern1 = replacement1)`), in order to perform multiple replacements\n#'   in each element of `string`.\n#'\n#'   Match a fixed string (i.e. by comparing only bytes), using\n#'   [fixed()]. This is fast, but approximate. Generally,\n#'   for matching human text, you'll want [coll()] which\n#'   respects character matching rules for the specified locale.\n#'\n#'   You can not match boundaries, including `\"\"`, with this function.\n#' @param replacement The replacement value, usually a single string,\n#'   but it can be the a vector the same length as `string` or `pattern`.\n#'   References of the form `\\1`, `\\2`, etc will be replaced with\n#'   the contents of the respective matched group (created by `()`).\n#'\n#'   Alternatively, supply a function (or formula): it will be passed a single\n#'   character vector and should return a character vector of the same length.\n#'\n#'   To replace the complete string with `NA`, use\n#'   `replacement = NA_character_`.\n#' @return A character vector the same length as\n#'   `string`/`pattern`/`replacement`.\n#' @seealso [str_replace_na()] to turn missing values into \"NA\";\n#'   [stringi::stri_replace()] for the underlying implementation.\n#' @export\n#' @examples\n#' fruits <- c(\"one apple\", \"two pears\", \"three bananas\")\n#' str_replace(fruits, \"[aeiou]\", \"-\")\n#' str_replace_all(fruits, \"[aeiou]\", \"-\")\n#' str_replace_all(fruits, \"[aeiou]\", toupper)\n#' str_replace_all(fruits, \"b\", NA_character_)\n#'\n#' str_replace(fruits, \"([aeiou])\", \"\")\n#' str_replace(fruits, \"([aeiou])\", \"\\\\1\\\\1\")\n#'\n#' # Note that str_replace() is vectorised along text, pattern, and replacement\n#' str_replace(fruits, \"[aeiou]\", c(\"1\", \"2\", \"3\"))\n#' str_replace(fruits, c(\"a\", \"e\", \"i\"), \"-\")\n#'\n#' # If you want to apply multiple patterns and replacements to the same\n#' # string, pass a named vector to pattern.\n#' fruits %>%\n#'   str_c(collapse = \"---\") %>%\n#'   str_replace_all(c(\"one\" = \"1\", \"two\" = \"2\", \"three\" = \"3\"))\n#'\n#' # Use a function for more sophisticated replacement. This example\n#' # replaces colour names with their hex values.\n#' colours <- str_c(\"\\\\b\", colors(), \"\\\\b\", collapse=\"|\")\n#' col2hex <- function(col) {\n#'   rgb <- col2rgb(col)\n#'   rgb(rgb[\"red\", ], rgb[\"green\", ], rgb[\"blue\", ], maxColorValue = 255)\n#' }\n#'\n#' x <- c(\n#'   \"Roses are red, violets are blue\",\n#'   \"My favourite colour is green\"\n#' )\n#' str_replace_all(x, colours, col2hex)\nstr_replace <- function(string, pattern, replacement) {\n  if (!missing(replacement) && is_replacement_fun(replacement)) {\n    replacement <- as_function(replacement)\n    return(str_transform(string, pattern, replacement))\n  }\n\n  check_lengths(string, pattern, replacement)\n\n  out <- switch(\n    type(pattern),\n    empty = no_empty(),\n    bound = no_boundary(),\n    fixed = stri_replace_first_fixed(\n      string,\n      pattern,\n      replacement,\n      opts_fixed = opts(pattern)\n    ),\n    coll = stri_replace_first_coll(\n      string,\n      pattern,\n      replacement,\n      opts_collator = opts(pattern)\n    ),\n    regex = stri_replace_first_regex(\n      string,\n      pattern,\n      fix_replacement(replacement),\n      opts_regex = opts(pattern)\n    )\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' @export\n#' @rdname str_replace\nstr_replace_all <- function(string, pattern, replacement) {\n  if (!missing(replacement) && is_replacement_fun(replacement)) {\n    replacement <- as_function(replacement)\n    return(str_transform_all(string, pattern, replacement))\n  }\n\n  if (!is.null(names(pattern))) {\n    vec <- FALSE\n    replacement <- unname(pattern)\n    pattern[] <- names(pattern)\n  } else {\n    check_lengths(string, pattern, replacement)\n    vec <- TRUE\n  }\n\n  out <- switch(\n    type(pattern),\n    empty = no_empty(),\n    bound = no_boundary(),\n    fixed = stri_replace_all_fixed(\n      string,\n      pattern,\n      replacement,\n      vectorize_all = vec,\n      opts_fixed = opts(pattern)\n    ),\n    coll = stri_replace_all_coll(\n      string,\n      pattern,\n      replacement,\n      vectorize_all = vec,\n      opts_collator = opts(pattern)\n    ),\n    regex = stri_replace_all_regex(\n      string,\n      pattern,\n      fix_replacement(replacement),\n      vectorize_all = vec,\n      opts_regex = opts(pattern)\n    )\n  )\n  preserve_names_if_possible(string, pattern, out)\n}\n\nis_replacement_fun <- function(x) {\n  is.function(x) || is_formula(x)\n}\n\nfix_replacement <- function(x, error_call = caller_env()) {\n  check_character(x, arg = \"replacement\", call = error_call)\n  vapply(x, fix_replacement_one, character(1), USE.NAMES = FALSE)\n}\n\nfix_replacement_one <- function(x) {\n  if (is.na(x)) {\n    return(x)\n  }\n\n  chars <- str_split(x, \"\")[[1]]\n  out <- character(length(chars))\n  escaped <- logical(length(chars))\n\n  in_escape <- FALSE\n  for (i in seq_along(chars)) {\n    escaped[[i]] <- in_escape\n    char <- chars[[i]]\n\n    if (in_escape) {\n      # Escape character not printed previously so must include here\n      if (char == \"$\") {\n        out[[i]] <- \"\\\\\\\\$\"\n      } else if (char >= \"0\" && char <= \"9\") {\n        out[[i]] <- paste0(\"$\", char)\n      } else {\n        out[[i]] <- paste0(\"\\\\\", char)\n      }\n\n      in_escape <- FALSE\n    } else {\n      if (char == \"$\") {\n        out[[i]] <- \"\\\\$\"\n      } else if (char == \"\\\\\") {\n        in_escape <- TRUE\n      } else {\n        out[[i]] <- char\n      }\n    }\n  }\n\n  # tibble::tibble(chars, out, escaped)\n  paste0(out, collapse = \"\")\n}\n\n\n#' Turn NA into \"NA\"\n#'\n#' @inheritParams str_replace\n#' @param replacement A single string.\n#' @export\n#' @examples\n#' str_replace_na(c(NA, \"abc\", \"def\"))\nstr_replace_na <- function(string, replacement = \"NA\") {\n  check_string(replacement)\n  copy_names(string, stri_replace_na(string, replacement))\n}\n\nstr_transform <- function(string, pattern, replacement) {\n  loc <- str_locate(string, pattern)\n  new <- replacement(str_sub(string, loc))\n  str_sub(string, loc, omit_na = TRUE) <- new\n  string\n}\n\nstr_transform_all <- function(\n  string,\n  pattern,\n  replacement,\n  error_call = caller_env()\n) {\n  locs <- str_locate_all(string, pattern)\n\n  old <- str_sub_all(string, locs)\n\n  # unchop list into a vector, apply replacement(), and then rechop back into\n  # a list\n  old_flat <- vctrs::list_unchop(old)\n  if (length(old_flat) == 0) {\n    # minor optimisation to avoid problems with the many replacement\n    # functions that use paste\n    new_flat <- character()\n  } else {\n    withCallingHandlers(\n      new_flat <- replacement(old_flat),\n      error = function(cnd) {\n        cli::cli_abort(\n          c(\n            tr_(\"Failed to apply {.arg replacement} function.\"),\n            i = tr_(\"It must accept a character vector of any length.\")\n          ),\n          parent = cnd,\n          call = error_call\n        )\n      }\n    )\n  }\n\n  if (!is.character(new_flat)) {\n    cli::cli_abort(\n      tr_(\n        \"{.arg replacement} function must return a character vector, not {.obj_type_friendly {new_flat}}.\"\n      ),\n      call = error_call\n    )\n  }\n  if (length(new_flat) != length(old_flat)) {\n    cli::cli_abort(\n      tr_(\n        \"{.arg replacement} function must return a vector the same length as the input ({length(old_flat)}), not length {length(new_flat)}.\"\n      ),\n      call = error_call\n    )\n  }\n\n  idx <- chop_index(old)\n  new <- vctrs::vec_chop(new_flat, idx)\n\n  stringi::stri_sub_all(string, locs) <- new\n  string\n}\n\nchop_index <- function(x) {\n  ls <- lengths(x)\n  start <- cumsum(c(1L, ls[-length(ls)]))\n  end <- start + ls - 1L\n  lapply(seq_along(ls), function(i) seq2(start[[i]], end[[i]]))\n}\n"
  },
  {
    "path": "R/sort.R",
    "content": "#' Order, rank, or sort a character vector\n#'\n#' * `str_sort()` returns the sorted vector.\n#' * `str_order()` returns an integer vector that returns the desired\n#'   order when used for subsetting, i.e. `x[str_order(x)]` is the same\n#'   as `str_sort()`\n#' * `str_rank()` returns the ranks of the values, i.e.\n#'   `arrange(df, str_rank(x))` is the same as `str_sort(df$x)`.\n#'\n#' @param x A character vector to sort.\n#' @param decreasing A boolean. If `FALSE`, the default, sorts from\n#'   lowest to highest; if `TRUE` sorts from highest to lowest.\n#' @param na_last Where should `NA` go? `TRUE` at the end,\n#'   `FALSE` at the beginning, `NA` dropped.\n#' @param numeric If `TRUE`, will sort digits numerically, instead\n#'    of as strings.\n#' @param ... Other options used to control collation. Passed on to\n#'   [stringi::stri_opts_collator()].\n#' @inheritParams coll\n#' @return A character vector the same length as `string`.\n#' @seealso [stringi::stri_order()] for the underlying implementation.\n#' @export\n#' @examples\n#' x <- c(\"apple\", \"car\", \"happy\", \"char\")\n#' str_sort(x)\n#'\n#' str_order(x)\n#' x[str_order(x)]\n#'\n#' str_rank(x)\n#'\n#' # In Czech, ch is a digraph that sorts after h\n#' str_sort(x, locale = \"cs\")\n#'\n#' # Use numeric = TRUE to sort numbers in strings\n#' x <- c(\"100a10\", \"100a5\", \"2b\", \"2a\")\n#' str_sort(x)\n#' str_sort(x, numeric = TRUE)\nstr_order <- function(\n  x,\n  decreasing = FALSE,\n  na_last = TRUE,\n  locale = \"en\",\n  numeric = FALSE,\n  ...\n) {\n  check_bool(decreasing)\n  check_bool(na_last, allow_na = TRUE)\n  check_string(locale)\n  check_bool(numeric)\n\n  opts <- stri_opts_collator(locale, numeric = numeric, ...)\n  stri_order(\n    x,\n    decreasing = decreasing,\n    na_last = na_last,\n    opts_collator = opts\n  )\n}\n\n#' @export\n#' @rdname str_order\nstr_rank <- function(x, locale = \"en\", numeric = FALSE, ...) {\n  check_string(locale)\n  check_bool(numeric)\n\n  opts <- stri_opts_collator(locale, numeric = numeric, ...)\n  stri_rank(x, opts_collator = opts)\n}\n\n#' @export\n#' @rdname str_order\nstr_sort <- function(\n  x,\n  decreasing = FALSE,\n  na_last = TRUE,\n  locale = \"en\",\n  numeric = FALSE,\n  ...\n) {\n  check_bool(decreasing)\n  check_bool(na_last, allow_na = TRUE)\n  check_string(locale)\n  check_bool(numeric)\n\n  opts <- stri_opts_collator(locale, numeric = numeric, ...)\n  idx <- stri_order(\n    x,\n    decreasing = decreasing,\n    na_last = na_last,\n    opts_collator = opts\n  )\n  x[idx]\n}\n"
  },
  {
    "path": "R/split.R",
    "content": "#' Split up a string into pieces\n#'\n#' @description\n#' This family of functions provides various ways of splitting a string up\n#' into pieces. These two functions return a character vector:\n#'\n#' * `str_split_1()` takes a single string and splits it into pieces,\n#'    returning a single character vector.\n#' * `str_split_i()` splits each string in a character vector into pieces and\n#'    extracts the `i`th value, returning a character vector.\n#'\n#' These two functions return a more complex object:\n#'\n#' * `str_split()` splits each string in a character vector into a varying\n#'    number of pieces, returning a list of character vectors.\n#' * `str_split_fixed()` splits each string in a character vector into a\n#'    fixed number of pieces, returning a character matrix.\n#'\n#' @inheritParams str_extract\n#' @param n Maximum number of pieces to return. Default (Inf) uses all\n#'   possible split positions.\n#'\n#'   For `str_split()`, this determines the maximum length of each element\n#'   of the output. For `str_split_fixed()`, this determines the number of\n#'   columns in the output; if an input is too short, the result will be padded\n#'   with `\"\"`.\n#' @return\n#' * `str_split_1()`: a character vector.\n#' * `str_split()`: a list the same length as `string`/`pattern` containing\n#'   character vectors.\n#' * `str_split_fixed()`: a character matrix with `n` columns and the same\n#'   number of rows as the length of `string`/`pattern`.\n#' * `str_split_i()`: a character vector the same length as `string`/`pattern`.\n#' @seealso [stringi::stri_split()] for the underlying implementation.\n#' @export\n#' @examples\n#' fruits <- c(\n#'   \"apples and oranges and pears and bananas\",\n#'   \"pineapples and mangos and guavas\"\n#' )\n#'\n#' str_split(fruits, \" and \")\n#' str_split(fruits, \" and \", simplify = TRUE)\n#'\n#' # If you want to split a single string, use `str_split_1`\n#' str_split_1(fruits[[1]], \" and \")\n#'\n#' # Specify n to restrict the number of possible matches\n#' str_split(fruits, \" and \", n = 3)\n#' str_split(fruits, \" and \", n = 2)\n#' # If n greater than number of pieces, no padding occurs\n#' str_split(fruits, \" and \", n = 5)\n#'\n#' # Use fixed to return a character matrix\n#' str_split_fixed(fruits, \" and \", 3)\n#' str_split_fixed(fruits, \" and \", 4)\n#'\n#' # str_split_i extracts only a single piece from a string\n#' str_split_i(fruits, \" and \", 1)\n#' str_split_i(fruits, \" and \", 4)\n#' # use a negative number to select from the end\n#' str_split_i(fruits, \" and \", -1)\nstr_split <- function(string, pattern, n = Inf, simplify = FALSE) {\n  check_lengths(string, pattern)\n  check_positive_integer(n)\n  check_bool(simplify, allow_na = TRUE)\n\n  if (identical(n, Inf)) {\n    n <- -1L\n  }\n\n  out <- switch(\n    type(pattern),\n    empty = stri_split_boundaries(\n      string,\n      n = n,\n      simplify = simplify,\n      opts_brkiter = opts(pattern)\n    ),\n    bound = stri_split_boundaries(\n      string,\n      n = n,\n      simplify = simplify,\n      opts_brkiter = opts(pattern)\n    ),\n    fixed = stri_split_fixed(\n      string,\n      pattern,\n      n = n,\n      simplify = simplify,\n      opts_fixed = opts(pattern)\n    ),\n    regex = stri_split_regex(\n      string,\n      pattern,\n      n = n,\n      simplify = simplify,\n      opts_regex = opts(pattern)\n    ),\n    coll = stri_split_coll(\n      string,\n      pattern,\n      n = n,\n      simplify = simplify,\n      opts_collator = opts(pattern)\n    )\n  )\n\n  preserve_names_if_possible(string, pattern, out)\n}\n\n#' @export\n#' @rdname str_split\nstr_split_1 <- function(string, pattern) {\n  check_string(string)\n\n  str_split(string, pattern)[[1]]\n}\n\n#' @export\n#' @rdname str_split\nstr_split_fixed <- function(string, pattern, n) {\n  check_lengths(string, pattern)\n  check_positive_integer(n)\n\n  str_split(string, pattern, n = n, simplify = TRUE)\n}\n\n#' @export\n#' @rdname str_split\n#' @param i Element to return. Use a negative value to count from the\n#'   right hand side.\nstr_split_i <- function(string, pattern, i) {\n  check_number_whole(i)\n\n  if (i > 0) {\n    out <- str_split(string, pattern, simplify = NA, n = i + 1)\n    col <- out[, i]\n    if (keep_names(string, pattern)) copy_names(string, col) else col\n  } else if (i < 0) {\n    i <- abs(i)\n    pieces <- str_split(string, pattern)\n    last <- function(x) {\n      n <- length(x)\n      if (i > n) {\n        NA_character_\n      } else {\n        x[[n + 1 - i]]\n      }\n    }\n    out <- map_chr(pieces, last)\n    preserve_names_if_possible(string, pattern, out)\n  } else {\n    cli::cli_abort(tr_(\"{.arg i} must not be 0.\"))\n  }\n}\n\ncheck_positive_integer <- function(\n  x,\n  arg = caller_arg(x),\n  call = caller_env()\n) {\n  if (!identical(x, Inf)) {\n    check_number_whole(x, min = 1, arg = arg, call = call)\n  }\n}\n"
  },
  {
    "path": "R/stringr-package.R",
    "content": "#' @keywords internal\n\"_PACKAGE\"\n\n## usethis namespace: start\n#' @import stringi\n#' @import rlang\n#' @importFrom glue glue\n#' @importFrom lifecycle deprecated\n## usethis namespace: end\nNULL\n"
  },
  {
    "path": "R/sub.R",
    "content": "#' Get and set substrings using their positions\n#'\n#' `str_sub()` extracts or replaces the elements at a single position in each\n#' string. `str_sub_all()` allows you to extract strings at multiple elements\n#' in every string.\n#'\n#' @inheritParams str_detect\n#' @param start,end A pair of integer vectors defining the range of characters\n#'   to extract (inclusive). Positive values count from the left of the string,\n#'   and negative values count from the right. In other words, if `string` is\n#'   `\"abcdef\"` then 1 refers to `\"a\"` and -1 refers to `\"f\"`.\n#'\n#'   Alternatively, instead of a pair of vectors, you can pass a matrix to\n#'   `start`. The matrix should have two columns, either labelled `start`\n#'   and `end`, or `start` and `length`. This makes `str_sub()` work directly\n#'   with the output from [str_locate()] and friends.\n#'\n#' @param omit_na Single logical value. If `TRUE`, missing values in any of the\n#'   arguments provided will result in an unchanged input.\n#' @param value Replacement string.\n#' @return\n#' * `str_sub()`: A character vector the same length as `string`/`start`/`end`.\n#' * `str_sub_all()`: A list the same length as `string`. Each element is\n#'    a character vector the same length as `start`/`end`.\n#'\n#' If `end` comes before `start` or `start` is outside the range of `string`\n#' then the corresponding output will be the empty string.\n#' @seealso The underlying implementation in [stringi::stri_sub()]\n#' @export\n#' @examples\n#' hw <- \"Hadley Wickham\"\n#'\n#' str_sub(hw, 1, 6)\n#' str_sub(hw, end = 6)\n#' str_sub(hw, 8, 14)\n#' str_sub(hw, 8)\n#'\n#' # Negative values index from end of string\n#' str_sub(hw, -1)\n#' str_sub(hw, -7)\n#' str_sub(hw, end = -7)\n#'\n#' # str_sub() is vectorised by both string and position\n#' str_sub(hw, c(1, 8), c(6, 14))\n#'\n#' # if you want to extract multiple positions from multiple strings,\n#' # use str_sub_all()\n#' x <- c(\"abcde\", \"ghifgh\")\n#' str_sub(x, c(1, 2), c(2, 4))\n#' str_sub_all(x, start = c(1, 2), end = c(2, 4))\n#'\n#' # Alternatively, you can pass in a two column matrix, as in the\n#' # output from str_locate_all\n#' pos <- str_locate_all(hw, \"[aeio]\")[[1]]\n#' pos\n#' str_sub(hw, pos)\n#'\n#' # You can also use `str_sub()` to modify strings:\n#' x <- \"BBCDEF\"\n#' str_sub(x, 1, 1) <- \"A\"; x\n#' str_sub(x, -1, -1) <- \"K\"; x\n#' str_sub(x, -2, -2) <- \"GHIJ\"; x\n#' str_sub(x, 2, -2) <- \"\"; x\nstr_sub <- function(string, start = 1L, end = -1L) {\n  vctrs::vec_size_common(string = string, start = start, end = end)\n\n  out <- if (is.matrix(start)) {\n    stri_sub(string, from = start)\n  } else {\n    stri_sub(string, from = start, to = end)\n  }\n  # Preserve names unless `string` is recycled\n  if (length(out) == length(string)) copy_names(string, out) else out\n}\n\n\n#' @export\n#' @rdname str_sub\n\"str_sub<-\" <- function(string, start = 1L, end = -1L, omit_na = FALSE, value) {\n  vctrs::vec_size_common(\n    string = string,\n    start = start,\n    end = end,\n    value = value\n  )\n\n  if (is.matrix(start)) {\n    stri_sub(string, from = start, omit_na = omit_na) <- value\n  } else {\n    stri_sub(string, from = start, to = end, omit_na = omit_na) <- value\n  }\n  string\n}\n\n#' @export\n#' @rdname str_sub\nstr_sub_all <- function(string, start = 1L, end = -1L) {\n  out <- if (is.matrix(start)) {\n    stri_sub_all(string, from = start)\n  } else {\n    stri_sub_all(string, from = start, to = end)\n  }\n  copy_names(string, out)\n}\n"
  },
  {
    "path": "R/subset.R",
    "content": "#' Find matching elements\n#'\n#' @description\n#' `str_subset()` returns all elements of `string` where there's at least\n#' one match to `pattern`. It's a wrapper around `x[str_detect(x, pattern)]`,\n#' and is equivalent to `grep(pattern, x, value = TRUE)`.\n#'\n#' Use [str_extract()] to find the location of the match _within_ each string.\n#'\n#' @inheritParams str_detect\n#' @return A character vector, usually smaller than `string`.\n#' @seealso [grep()] with argument `value = TRUE`,\n#'    [stringi::stri_subset()] for the underlying implementation.\n#' @export\n#' @examples\n#' fruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n#' str_subset(fruit, \"a\")\n#'\n#' str_subset(fruit, \"^a\")\n#' str_subset(fruit, \"a$\")\n#' str_subset(fruit, \"b\")\n#' str_subset(fruit, \"[aeiou]\")\n#'\n#' # Elements that don't match\n#' str_subset(fruit, \"^p\", negate = TRUE)\n#'\n#' # Missings never match\n#' str_subset(c(\"a\", NA, \"b\"), \".\")\nstr_subset <- function(string, pattern, negate = FALSE) {\n  check_lengths(string, pattern)\n  check_bool(negate)\n\n  idx <- switch(\n    type(pattern),\n    empty = no_empty(),\n    bound = no_boundary(),\n    fixed = str_detect(string, pattern, negate = negate),\n    coll = str_detect(string, pattern, negate = negate),\n    regex = str_detect(string, pattern, negate = negate)\n  )\n\n  idx[is.na(idx)] <- FALSE\n  string[idx]\n}\n\n#' Find matching indices\n#'\n#' `str_which()` returns the indices of `string` where there's at least\n#' one match to `pattern`. It's a wrapper around\n#' `which(str_detect(x, pattern))`, and is equivalent to `grep(pattern, x)`.\n#'\n#' @inheritParams str_detect\n#' @return An integer vector, usually smaller than `string`.\n#' @export\n#' @examples\n#' fruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n#' str_which(fruit, \"a\")\n#'\n#' # Elements that don't match\n#' str_which(fruit, \"^p\", negate = TRUE)\n#'\n#' # Missings never match\n#' str_which(c(\"a\", NA, \"b\"), \".\")\nstr_which <- function(string, pattern, negate = FALSE) {\n  which(str_detect(string, pattern, negate = negate))\n}\n"
  },
  {
    "path": "R/trim.R",
    "content": "#' Remove whitespace\n#'\n#' `str_trim()` removes whitespace from start and end of string; `str_squish()`\n#' removes whitespace at the start and end, and replaces all internal whitespace\n#' with a single space.\n#'\n#' @inheritParams str_detect\n#' @param side Side on which to remove whitespace: \"left\", \"right\", or\n#'   \"both\", the default.\n#' @return A character vector the same length as `string`.\n#' @export\n#' @seealso [str_pad()] to add whitespace\n#' @examples\n#' str_trim(\"  String with trailing and leading white space\\t\")\n#' str_trim(\"\\n\\nString with trailing and leading white space\\n\\n\")\n#'\n#' str_squish(\"  String with trailing,  middle, and leading white space\\t\")\n#' str_squish(\"\\n\\nString with excess,  trailing and leading white   space\\n\\n\")\nstr_trim <- function(string, side = c(\"both\", \"left\", \"right\")) {\n  side <- arg_match(side)\n\n  out <- switch(\n    side,\n    left = stri_trim_left(string),\n    right = stri_trim_right(string),\n    both = stri_trim_both(string)\n  )\n  copy_names(string, out)\n}\n\n#' @export\n#' @rdname str_trim\nstr_squish <- function(string) {\n  copy_names(string, stri_trim_both(str_replace_all(string, \"\\\\s+\", \" \")))\n}\n"
  },
  {
    "path": "R/trunc.R",
    "content": "#' Truncate a string to maximum width\n#'\n#' Truncate a string to a fixed of characters, so that\n#' `str_length(str_trunc(x, n))` is always less than or equal to `n`.\n#'\n#' @inheritParams str_detect\n#' @param width Maximum width of string.\n#' @param side,ellipsis Location and content of ellipsis that indicates\n#'   content has been removed.\n#' @return A character vector the same length as `string`.\n#' @seealso [str_pad()] to increase the minimum width of a string.\n#' @export\n#' @examples\n#' x <- \"This string is moderately long\"\n#' rbind(\n#'   str_trunc(x, 20, \"right\"),\n#'   str_trunc(x, 20, \"left\"),\n#'   str_trunc(x, 20, \"center\")\n#' )\nstr_trunc <- function(\n  string,\n  width,\n  side = c(\"right\", \"left\", \"center\"),\n  ellipsis = \"...\"\n) {\n  check_number_whole(width)\n  side <- arg_match(side)\n  check_string(ellipsis)\n\n  len <- str_length(string)\n  too_long <- !is.na(string) & len > width\n  width... <- width - str_length(ellipsis)\n\n  if (width... < 0) {\n    cli::cli_abort(\n      tr_(\n        \"`width` ({width}) is shorter than `ellipsis` ({str_length(ellipsis)}).\"\n      )\n    )\n  }\n\n  string[too_long] <- switch(\n    side,\n    right = str_c(str_sub(string[too_long], 1, width...), ellipsis),\n    left = str_c(\n      ellipsis,\n      str_sub(string[too_long], len[too_long] - width... + 1, -1)\n    ),\n    center = str_c(\n      str_sub(string[too_long], 1, ceiling(width... / 2)),\n      ellipsis,\n      str_sub(string[too_long], len[too_long] - floor(width... / 2) + 1, -1)\n    )\n  )\n  string\n}\n"
  },
  {
    "path": "R/unique.R",
    "content": "#' Remove duplicated strings\n#'\n#' `str_unique()` removes duplicated values, with optional control over\n#' how duplication is measured.\n#'\n#' @inheritParams str_detect\n#' @inheritParams str_equal\n#' @return A character vector, usually shorter than `string`.\n#' @seealso [unique()], [stringi::stri_unique()] which this function wraps.\n#' @examples\n#' str_unique(c(\"a\", \"b\", \"c\", \"b\", \"a\"))\n#'\n#' str_unique(c(\"a\", \"b\", \"c\", \"B\", \"A\"))\n#' str_unique(c(\"a\", \"b\", \"c\", \"B\", \"A\"), ignore_case = TRUE)\n#'\n#' # Use ... to pass additional arguments to stri_unique()\n#' str_unique(c(\"motley\", \"mötley\", \"pinguino\", \"pingüino\"))\n#' str_unique(c(\"motley\", \"mötley\", \"pinguino\", \"pingüino\"), strength = 1)\n#' @export\nstr_unique <- function(string, locale = \"en\", ignore_case = FALSE, ...) {\n  check_string(locale)\n  check_bool(ignore_case)\n\n  opts <- str_opts_collator(\n    locale = locale,\n    ignore_case = ignore_case,\n    ...\n  )\n\n  keep <- !stringi::stri_duplicated(string, opts_collator = opts)\n  string[keep]\n}\n"
  },
  {
    "path": "R/utils.R",
    "content": "#' Pipe operator\n#'\n#' @name %>%\n#' @rdname pipe\n#' @keywords internal\n#' @export\n#' @importFrom magrittr %>%\n#' @usage lhs \\%>\\% rhs\nNULL\n\ncheck_lengths <- function(\n  string,\n  pattern,\n  replacement = NULL,\n  error_call = caller_env()\n) {\n  # stringi already correctly recycles vectors of length 0 and 1\n  # we just want more stringent vctrs checks for other lengths\n  vctrs::vec_size_common(\n    string = string,\n    pattern = pattern,\n    replacement = replacement,\n    .call = error_call\n  )\n}\n\nno_boundary <- function(call = caller_env()) {\n  cli::cli_abort(tr_(\"{.arg pattern} can't be a boundary.\"), call = call)\n}\nno_empty <- function(call = caller_env()) {\n  cli::cli_abort(\n    tr_(\"{.arg pattern} can't be the empty string ({.code \\\"\\\"}).\"),\n    call = call\n  )\n}\n\ntr_ <- function(...) {\n  enc2utf8(gettext(paste0(...), domain = \"R-stringr\"))\n}\n\n# copy names from `string` to output, regardless of output type\ncopy_names <- function(from, to) {\n  nm <- names(from)\n  if (is.null(nm)) {\n    return(to)\n  }\n\n  if (is.matrix(to)) {\n    rownames(to) <- nm\n    to\n  } else {\n    set_names(to, nm)\n  }\n}\n\n# keep names if pattern is scalar (i.e. vectorised) or same length as string.\nkeep_names <- function(string, pattern) {\n  length(pattern) == 1L || length(pattern) == length(string)\n}\n\npreserve_names_if_possible <- function(string, pattern, out) {\n  if (keep_names(string, pattern)) {\n    copy_names(string, out)\n  } else {\n    out\n  }\n}\n"
  },
  {
    "path": "R/view.R",
    "content": "#' View strings and matches\n#'\n#' @description\n#' `str_view()` is used to print the underlying representation of a string and\n#' to see how a `pattern` matches.\n#'\n#' Matches are surrounded by `<>` and unusual whitespace (i.e. all whitespace\n#' apart from `\" \"` and `\"\\n\"`) are surrounded by `{}` and escaped. Where\n#' possible, matches and unusual whitespace are coloured blue and `NA`s red.\n#'\n#' @inheritParams str_detect\n#' @param match If `pattern` is supplied, which elements should be shown?\n#'\n#'   * `TRUE`, the default, shows only elements that match the pattern.\n#'   * `NA` shows all elements.\n#'   * `FALSE` shows only elements that don't match the pattern.\n#'\n#'   If `pattern` is not supplied, all elements are always shown.\n#' @param html Use HTML output? If `TRUE` will create an HTML widget; if `FALSE`\n#'   will style using ANSI escapes.\n#' @param use_escapes If `TRUE`, all non-ASCII characters will be rendered\n#'   with unicode escapes. This is useful to see exactly what underlying\n#'   values are stored in the string.\n#' @export\n#' @examples\n#' # Show special characters\n#' str_view(c(\"\\\"\\\\\", \"\\\\\\\\\\\\\", \"fgh\", NA, \"NA\"))\n#'\n#' # A non-breaking space looks like a regular space:\n#' nbsp <- \"Hi\\u00A0you\"\n#' nbsp\n#' # But it doesn't behave like one:\n#' str_detect(nbsp, \" \")\n#' # So str_view() brings it to your attention with a blue background\n#' str_view(nbsp)\n#'\n#' # You can also use escapes to see all non-ASCII characters\n#' str_view(nbsp, use_escapes = TRUE)\n#'\n#' # Supply a pattern to see where it matches\n#' str_view(c(\"abc\", \"def\", \"fghi\"), \"[aeiou]\")\n#' str_view(c(\"abc\", \"def\", \"fghi\"), \"^\")\n#' str_view(c(\"abc\", \"def\", \"fghi\"), \"..\")\n#'\n#' # By default, only matching strings will be shown\n#' str_view(c(\"abc\", \"def\", \"fghi\"), \"e\")\n#' # but you can show all:\n#' str_view(c(\"abc\", \"def\", \"fghi\"), \"e\", match = NA)\n#' # or just those that don't match:\n#' str_view(c(\"abc\", \"def\", \"fghi\"), \"e\", match = FALSE)\nstr_view <- function(\n  string,\n  pattern = NULL,\n  match = TRUE,\n  html = FALSE,\n  use_escapes = FALSE\n) {\n  rec <- vctrs::vec_recycle_common(string = string, pattern = pattern)\n  string <- rec$string\n  pattern <- rec$pattern\n\n  check_bool(match, allow_na = TRUE)\n  check_bool(html)\n  check_bool(use_escapes)\n\n  filter <- str_view_filter(string, pattern, match)\n  out <- string[filter]\n  pattern <- pattern[filter]\n\n  if (!is.null(pattern)) {\n    out <- str_replace_all(out, pattern, str_view_highlighter(html))\n  }\n  if (use_escapes) {\n    out <- stri_escape_unicode(out)\n    out <- str_replace_all(out, fixed(\"\\\\u001b\"), \"\\u001b\")\n  } else {\n    out <- str_view_special(out, html = html)\n  }\n\n  str_view_print(out, filter, html = html)\n}\n\n#' @rdname str_view\n#' @usage NULL\n#' @export\nstr_view_all <- function(\n  string,\n  pattern = NULL,\n  match = NA,\n  html = FALSE,\n  use_escapes = FALSE\n) {\n  lifecycle::deprecate_warn(\"1.5.0\", \"str_view_all()\", \"str_view()\")\n\n  str_view(\n    string = string,\n    pattern = pattern,\n    match = match,\n    html = html,\n    use_escapes = use_escapes\n  )\n}\n\nstr_view_filter <- function(x, pattern, match) {\n  if (is.null(pattern) || inherits(pattern, \"stringr_boundary\")) {\n    rep(TRUE, length(x))\n  } else {\n    if (identical(match, TRUE)) {\n      str_detect(x, pattern) & !is.na(x)\n    } else if (identical(match, FALSE)) {\n      !str_detect(x, pattern) | is.na(x)\n    } else {\n      rep(TRUE, length(x))\n    }\n  }\n}\n\n# Helpers -----------------------------------------------------------------\n\nstr_view_highlighter <- function(html = TRUE) {\n  if (html) {\n    function(x) str_c(\"<span class='match'>\", x, \"</span>\")\n  } else {\n    function(x) {\n      out <- cli::col_cyan(\"<\", x, \">\")\n\n      # Ensure styling is starts and ends within each line\n      out <- cli::ansi_strsplit(out, \"\\n\", fixed = TRUE)\n      out <- map_chr(out, str_flatten, \"\\n\")\n\n      out\n    }\n  }\n}\n\nstr_view_special <- function(x, html = TRUE) {\n  if (html) {\n    replace <- function(x) str_c(\"<span class='special'>\", x, \"</span>\")\n  } else {\n    replace <- function(x) {\n      if (length(x) == 0) {\n        return(character())\n      }\n\n      cli::col_cyan(\"{\", stri_escape_unicode(x), \"}\")\n    }\n  }\n\n  # Highlight any non-standard whitespace characters\n  str_replace_all(x, \"[\\\\p{Whitespace}-- \\n]+\", replace)\n}\n\nstr_view_print <- function(x, filter, html = TRUE) {\n  if (html) {\n    str_view_widget(x)\n  } else {\n    structure(x, id = which(filter), class = \"stringr_view\")\n  }\n}\n\nstr_view_widget <- function(lines) {\n  check_installed(c(\"htmltools\", \"htmlwidgets\"))\n\n  lines <- str_replace_na(lines)\n  bullets <- str_c(\n    \"<ul>\\n\",\n    str_c(\"  <li><pre>\", lines, \"</pre></li>\", collapse = \"\\n\"),\n    \"\\n</ul>\"\n  )\n\n  html <- htmltools::HTML(bullets)\n  size <- htmlwidgets::sizingPolicy(\n    knitr.figure = FALSE,\n    defaultHeight = pmin(10 * length(lines), 300),\n    knitr.defaultHeight = \"100%\"\n  )\n\n  htmlwidgets::createWidget(\n    \"str_view\",\n    list(html = html),\n    sizingPolicy = size,\n    package = \"stringr\"\n  )\n}\n\n#' @export\nprint.stringr_view <- function(x, ..., n = getOption(\"stringr.view_n\", 20)) {\n  n_extra <- length(x) - n\n  if (n_extra > 0) {\n    x <- x[seq_len(n)]\n  }\n\n  if (length(x) == 0) {\n    cli::cli_inform(c(x = \"Empty `string` provided.\\n\"))\n    return(invisible(x))\n  }\n\n  bar <- if (cli::is_utf8_output()) \"\\u2502\" else \"|\"\n\n  id <- format(paste0(\"[\", attr(x, \"id\"), \"] \"), justify = \"right\")\n  indent <- paste0(cli::col_grey(id, bar), \" \")\n  exdent <- paste0(strrep(\" \", nchar(id[[1]])), cli::col_grey(bar), \" \")\n\n  x[is.na(x)] <- cli::col_red(\"NA\")\n  x <- paste0(indent, x)\n  x <- str_replace_all(x, \"\\n\", paste0(\"\\n\", exdent))\n\n  cat(x, sep = \"\\n\")\n  if (n_extra > 0) {\n    cat(\"... and \", n_extra, \" more\\n\", sep = \"\")\n  }\n\n  invisible(x)\n}\n\n#' @export\n`[.stringr_view` <- function(x, i, ...) {\n  structure(NextMethod(), id = attr(x, \"id\")[i], class = \"stringr_view\")\n}\n"
  },
  {
    "path": "R/word.R",
    "content": "#' Extract words from a sentence\n#'\n#' @inheritParams str_detect\n#' @param start,end Pair of integer vectors giving range of words (inclusive)\n#'   to extract. If negative, counts backwards from the last word.\n#'\n#'   The default value select the first word.\n#' @param sep Separator between words. Defaults to single space.\n#' @return A character vector with the same length as `string`/`start`/`end`.\n#' @export\n#' @examples\n#' sentences <- c(\"Jane saw a cat\", \"Jane sat down\")\n#' word(sentences, 1)\n#' word(sentences, 2)\n#' word(sentences, -1)\n#' word(sentences, 2, -1)\n#'\n#' # Also vectorised over start and end\n#' word(sentences[1], 1:3, -1)\n#' word(sentences[1], 1, 1:4)\n#'\n#' # Can define words by other separators\n#' str <- 'abc.def..123.4568.999'\n#' word(str, 1, sep = fixed('..'))\n#' word(str, 2, sep = fixed('..'))\nword <- function(string, start = 1L, end = start, sep = fixed(\" \")) {\n  args <- vctrs::vec_recycle_common(string = string, start = start, end = end)\n  string <- args$string\n  start <- args$start\n  end <- args$end\n\n  breaks <- str_locate_all(string, sep)\n  words <- lapply(breaks, invert_match)\n\n  # Convert negative values into actual positions\n  len <- vapply(words, nrow, integer(1))\n\n  neg_start <- !is.na(start) & start < 0L\n  start[neg_start] <- start[neg_start] + len[neg_start] + 1L\n\n  neg_end <- !is.na(end) & end < 0L\n  end[neg_end] <- end[neg_end] + len[neg_end] + 1L\n\n  # Replace indexes past end with NA\n  start[start > len] <- NA\n  end[end > len] <- NA\n\n  # To return all words when trying to extract more words than available\n  start[start < 1L] <- 1\n\n  # Extract locations\n  starts <- mapply(function(word, loc) word[loc, \"start\"], words, start)\n  ends <- mapply(function(word, loc) word[loc, \"end\"], words, end)\n\n  copy_names(string, str_sub(string, starts, ends))\n}\n"
  },
  {
    "path": "R/wrap.R",
    "content": "#' Wrap words into nicely formatted paragraphs\n#'\n#' Wrap words into paragraphs, minimizing the \"raggedness\" of the lines\n#' (i.e. the variation in length line) using the Knuth-Plass algorithm.\n#'\n#' @inheritParams str_detect\n#' @param width Positive integer giving target line width (in number of\n#'   characters). A width less than or equal to 1 will put each word on its\n#'   own line.\n#' @param indent,exdent A non-negative integer giving the indent for the\n#'   first line (`indent`) and all subsequent lines (`exdent`).\n#' @param whitespace_only A boolean.\n#'   * If `TRUE` (the default) wrapping will only occur at whitespace.\n#'   * If `FALSE`, can break on any non-word character (e.g. `/`, `-`).\n#' @return A character vector the same length as `string`.\n#' @seealso [stringi::stri_wrap()] for the underlying implementation.\n#' @export\n#' @examples\n#' thanks_path <- file.path(R.home(\"doc\"), \"THANKS\")\n#' thanks <- str_c(readLines(thanks_path), collapse = \"\\n\")\n#' thanks <- word(thanks, 1, 3, fixed(\"\\n\\n\"))\n#' cat(str_wrap(thanks), \"\\n\")\n#' cat(str_wrap(thanks, width = 40), \"\\n\")\n#' cat(str_wrap(thanks, width = 60, indent = 2), \"\\n\")\n#' cat(str_wrap(thanks, width = 60, exdent = 2), \"\\n\")\n#' cat(str_wrap(thanks, width = 0, exdent = 2), \"\\n\")\nstr_wrap <- function(\n  string,\n  width = 80,\n  indent = 0,\n  exdent = 0,\n  whitespace_only = TRUE\n) {\n  check_number_decimal(width)\n  if (width <= 0) {\n    width <- 1\n  }\n  check_number_whole(indent)\n  check_number_whole(exdent)\n  check_bool(whitespace_only)\n\n  out <- stri_wrap(\n    string,\n    width = width,\n    indent = indent,\n    exdent = exdent,\n    whitespace_only = whitespace_only,\n    simplify = FALSE\n  )\n  out <- vapply(out, str_c, collapse = \"\\n\", character(1))\n  copy_names(string, out)\n}\n"
  },
  {
    "path": "README.Rmd",
    "content": "---\noutput: github_document\n---\n\n<!-- README.md is generated from README.Rmd. Please edit that file -->\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#>\",\n  fig.path = \"README-\"\n)\nlibrary(stringr)\n```\n\n# stringr <a href='https://stringr.tidyverse.org'><img src='man/figures/logo.png' align=\"right\" height=\"139\" /></a>\n\n<!-- badges: start -->\n[![CRAN status](https://www.r-pkg.org/badges/version/stringr)](https://cran.r-project.org/package=stringr)\n[![R-CMD-check](https://github.com/tidyverse/stringr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tidyverse/stringr/actions/workflows/R-CMD-check.yaml)\n[![Codecov test coverage](https://codecov.io/gh/tidyverse/stringr/branch/main/graph/badge.svg)](https://app.codecov.io/gh/tidyverse/stringr?branch=main)\n[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable)\n<!-- badges: end -->\n\n## Overview\n\nStrings are not glamorous, high-profile components of R, but they do play a big role in many data cleaning and preparation tasks. The stringr package provides a cohesive set of functions designed to make working with strings as easy as possible. If you're not familiar with strings, the best place to start is the [chapter on strings](https://r4ds.hadley.nz/strings) in R for Data Science.\n\nstringr is built on top of [stringi](https://github.com/gagolews/stringi), which uses the [ICU](https://icu.unicode.org) C library to provide fast, correct implementations of common string manipulations. stringr focusses on the most important and commonly used string manipulation functions whereas stringi provides a comprehensive set covering almost anything you can imagine. If you find that stringr is missing a function that you need, try looking in stringi. Both packages share similar conventions, so once you've mastered stringr, you should find stringi similarly easy to use.\n\n## Installation\n\n```r\n# The easiest way to get stringr is to install the whole tidyverse:\ninstall.packages(\"tidyverse\")\n\n# Alternatively, install just stringr:\ninstall.packages(\"stringr\")\n```\n\n## Cheatsheet\n\n<a href=\"https://github.com/rstudio/cheatsheets/blob/main/strings.pdf\"><img src=\"https://raw.githubusercontent.com/rstudio/cheatsheets/main/pngs/thumbnails/strings-cheatsheet-thumbs.png\" width=\"630\" height=\"242\"/></a>  \n\n## Usage\n\nAll functions in stringr start with `str_` and take a vector of strings as the first argument:\n\n```{r}\nx <- c(\"why\", \"video\", \"cross\", \"extra\", \"deal\", \"authority\")\nstr_length(x) \nstr_c(x, collapse = \", \")\nstr_sub(x, 1, 2)\n```\n\nMost string functions work with regular expressions, a concise language for describing patterns of text. For example, the regular expression `\"[aeiou]\"` matches any single character that is a vowel:\n\n```{r}\nstr_subset(x, \"[aeiou]\")\nstr_count(x, \"[aeiou]\")\n```\n\nThere are seven main verbs that work with patterns:\n\n*   `str_detect(x, pattern)` tells you if there's any match to the pattern:\n    ```{r}\n    str_detect(x, \"[aeiou]\")\n    ```\n    \n*   `str_count(x, pattern)` counts the number of patterns:\n    ```{r}\n    str_count(x, \"[aeiou]\")\n    ```\n\n*   `str_subset(x, pattern)` extracts the matching components:\n    ```{r}\n    str_subset(x, \"[aeiou]\")\n    ```\n\n*   `str_locate(x, pattern)` gives the position of the match:\n    ```{r}\n    str_locate(x, \"[aeiou]\")\n    ```\n\n*   `str_extract(x, pattern)` extracts the text of the match:\n    ```{r}\n    str_extract(x, \"[aeiou]\")\n    ```\n\n*   `str_match(x, pattern)` extracts parts of the match defined by parentheses:\n    ```{r}\n    # extract the characters on either side of the vowel\n    str_match(x, \"(.)[aeiou](.)\")\n    ```\n\n*   `str_replace(x, pattern, replacement)` replaces the matches with new text:\n    ```{r}\n    str_replace(x, \"[aeiou]\", \"?\")\n    ```\n\n*   `str_split(x, pattern)` splits up a string into multiple pieces:\n    ```{r}\n    str_split(c(\"a,b\", \"c,d,e\"), \",\")\n    ```\n\nAs well as regular expressions (the default), there are three other pattern matching engines:\n\n* `fixed()`: match exact bytes\n* `coll()`: match human letters\n* `boundary()`: match boundaries\n\n## RStudio Addin\n\nThe [RegExplain RStudio addin](https://www.garrickadenbuie.com/project/regexplain/) provides a friendly interface for working with regular expressions and functions from stringr. This addin allows you to interactively build your regexp, check the output of common string matching functions, consult the interactive help pages, or use the included resources to learn regular expressions.\n\nThis addin can easily be installed with devtools:\n\n```r\n# install.packages(\"devtools\")\ndevtools::install_github(\"gadenbuie/regexplain\")\n```\n\n## Compared to base R\n\nR 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. \n\n* Uses consistent function and argument names. The first argument is always\n  the vector of strings to modify, which makes stringr work particularly well\n  in conjunction with the pipe:\n  \n    ```{r}\n    letters %>%\n      .[1:10] %>% \n      str_pad(3, \"right\") %>%\n      str_c(letters[2:11])\n    ```\n\n* Simplifies string operations by eliminating options that you don't need\n  95% of the time.\n\n* Produces outputs than can easily be used as inputs. This includes ensuring\n  that missing inputs result in missing outputs, and zero length inputs\n  result in zero length outputs.\n  \nLearn more in `vignette(\"from-base\")`\n"
  },
  {
    "path": "README.md",
    "content": "\n<!-- README.md is generated from README.Rmd. Please edit that file -->\n\n# stringr <a href='https://stringr.tidyverse.org'><img src='man/figures/logo.png' align=\"right\" height=\"139\" /></a>\n\n<!-- badges: start -->\n\n[![CRAN\nstatus](https://www.r-pkg.org/badges/version/stringr)](https://cran.r-project.org/package=stringr)\n[![R-CMD-check](https://github.com/tidyverse/stringr/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tidyverse/stringr/actions/workflows/R-CMD-check.yaml)\n[![Codecov test\ncoverage](https://codecov.io/gh/tidyverse/stringr/branch/main/graph/badge.svg)](https://app.codecov.io/gh/tidyverse/stringr?branch=main)\n[![Lifecycle:\nstable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable)\n<!-- badges: end -->\n\n## Overview\n\nStrings are not glamorous, high-profile components of R, but they do\nplay a big role in many data cleaning and preparation tasks. The stringr\npackage provides a cohesive set of functions designed to make working\nwith strings as easy as possible. If you’re not familiar with strings,\nthe best place to start is the [chapter on\nstrings](https://r4ds.hadley.nz/strings) in R for Data Science.\n\nstringr is built on top of\n[stringi](https://github.com/gagolews/stringi), which uses the\n[ICU](https://icu.unicode.org) C library to provide fast, correct\nimplementations of common string manipulations. stringr focusses on the\nmost important and commonly used string manipulation functions whereas\nstringi provides a comprehensive set covering almost anything you can\nimagine. If you find that stringr is missing a function that you need,\ntry looking in stringi. Both packages share similar conventions, so once\nyou’ve mastered stringr, you should find stringi similarly easy to use.\n\n## Installation\n\n``` r\n# The easiest way to get stringr is to install the whole tidyverse:\ninstall.packages(\"tidyverse\")\n\n# Alternatively, install just stringr:\ninstall.packages(\"stringr\")\n```\n\n## Cheatsheet\n\n<a href=\"https://github.com/rstudio/cheatsheets/blob/main/strings.pdf\"><img src=\"https://raw.githubusercontent.com/rstudio/cheatsheets/main/pngs/thumbnails/strings-cheatsheet-thumbs.png\" width=\"630\" height=\"242\"/></a>\n\n## Usage\n\nAll functions in stringr start with `str_` and take a vector of strings\nas the first argument:\n\n``` r\nx <- c(\"why\", \"video\", \"cross\", \"extra\", \"deal\", \"authority\")\nstr_length(x) \n#> [1] 3 5 5 5 4 9\nstr_c(x, collapse = \", \")\n#> [1] \"why, video, cross, extra, deal, authority\"\nstr_sub(x, 1, 2)\n#> [1] \"wh\" \"vi\" \"cr\" \"ex\" \"de\" \"au\"\n```\n\nMost string functions work with regular expressions, a concise language\nfor describing patterns of text. For example, the regular expression\n`\"[aeiou]\"` matches any single character that is a vowel:\n\n``` r\nstr_subset(x, \"[aeiou]\")\n#> [1] \"video\"     \"cross\"     \"extra\"     \"deal\"      \"authority\"\nstr_count(x, \"[aeiou]\")\n#> [1] 0 3 1 2 2 4\n```\n\nThere are seven main verbs that work with patterns:\n\n- `str_detect(x, pattern)` tells you if there’s any match to the\n  pattern:\n\n  ``` r\n  str_detect(x, \"[aeiou]\")\n  #> [1] FALSE  TRUE  TRUE  TRUE  TRUE  TRUE\n  ```\n\n- `str_count(x, pattern)` counts the number of patterns:\n\n  ``` r\n  str_count(x, \"[aeiou]\")\n  #> [1] 0 3 1 2 2 4\n  ```\n\n- `str_subset(x, pattern)` extracts the matching components:\n\n  ``` r\n  str_subset(x, \"[aeiou]\")\n  #> [1] \"video\"     \"cross\"     \"extra\"     \"deal\"      \"authority\"\n  ```\n\n- `str_locate(x, pattern)` gives the position of the match:\n\n  ``` r\n  str_locate(x, \"[aeiou]\")\n  #>      start end\n  #> [1,]    NA  NA\n  #> [2,]     2   2\n  #> [3,]     3   3\n  #> [4,]     1   1\n  #> [5,]     2   2\n  #> [6,]     1   1\n  ```\n\n- `str_extract(x, pattern)` extracts the text of the match:\n\n  ``` r\n  str_extract(x, \"[aeiou]\")\n  #> [1] NA  \"i\" \"o\" \"e\" \"e\" \"a\"\n  ```\n\n- `str_match(x, pattern)` extracts parts of the match defined by\n  parentheses:\n\n  ``` r\n  # extract the characters on either side of the vowel\n  str_match(x, \"(.)[aeiou](.)\")\n  #>      [,1]  [,2] [,3]\n  #> [1,] NA    NA   NA  \n  #> [2,] \"vid\" \"v\"  \"d\" \n  #> [3,] \"ros\" \"r\"  \"s\" \n  #> [4,] NA    NA   NA  \n  #> [5,] \"dea\" \"d\"  \"a\" \n  #> [6,] \"aut\" \"a\"  \"t\"\n  ```\n\n- `str_replace(x, pattern, replacement)` replaces the matches with new\n  text:\n\n  ``` r\n  str_replace(x, \"[aeiou]\", \"?\")\n  #> [1] \"why\"       \"v?deo\"     \"cr?ss\"     \"?xtra\"     \"d?al\"      \"?uthority\"\n  ```\n\n- `str_split(x, pattern)` splits up a string into multiple pieces:\n\n  ``` r\n  str_split(c(\"a,b\", \"c,d,e\"), \",\")\n  #> [[1]]\n  #> [1] \"a\" \"b\"\n  #> \n  #> [[2]]\n  #> [1] \"c\" \"d\" \"e\"\n  ```\n\nAs well as regular expressions (the default), there are three other\npattern matching engines:\n\n- `fixed()`: match exact bytes\n- `coll()`: match human letters\n- `boundary()`: match boundaries\n\n## RStudio Addin\n\nThe [RegExplain RStudio\naddin](https://www.garrickadenbuie.com/project/regexplain/) provides a\nfriendly interface for working with regular expressions and functions\nfrom stringr. This addin allows you to interactively build your regexp,\ncheck the output of common string matching functions, consult the\ninteractive help pages, or use the included resources to learn regular\nexpressions.\n\nThis addin can easily be installed with devtools:\n\n``` r\n# install.packages(\"devtools\")\ndevtools::install_github(\"gadenbuie/regexplain\")\n```\n\n## Compared to base R\n\nR provides a solid set of string operations, but because they have grown\norganically over time, they can be inconsistent and a little hard to\nlearn. Additionally, they lag behind the string operations in other\nprogramming languages, so that some things that are easy to do in\nlanguages like Ruby or Python are rather hard to do in R.\n\n- Uses consistent function and argument names. The first argument is\n  always the vector of strings to modify, which makes stringr work\n  particularly well in conjunction with the pipe:\n\n  ``` r\n  letters %>%\n    .[1:10] %>% \n    str_pad(3, \"right\") %>%\n    str_c(letters[2:11])\n  #>  [1] \"a  b\" \"b  c\" \"c  d\" \"d  e\" \"e  f\" \"f  g\" \"g  h\" \"h  i\" \"i  j\" \"j  k\"\n  ```\n\n- Simplifies string operations by eliminating options that you don’t\n  need 95% of the time.\n\n- Produces outputs than can easily be used as inputs. This includes\n  ensuring that missing inputs result in missing outputs, and zero\n  length inputs result in zero length outputs.\n\nLearn more in `vignette(\"from-base\")`\n"
  },
  {
    "path": "_pkgdown.yml",
    "content": "url: https://stringr.tidyverse.org\n\ndevelopment:\n  mode: auto\n\ntemplate:\n  package: tidytemplate\n  bootstrap: 5\n  includes:\n    in_header: |\n      <script src=\"https://cdn.jsdelivr.net/gh/posit-dev/supported-by-posit/js/badge.min.js\" data-max-height=\"43\" data-light-bg=\"#666f76\" data-light-fg=\"#f9f9f9\"></script>\n      <script defer data-domain=\"stringr.tidyverse.org,all.tidyverse.org\" src=\"https://plausible.io/js/plausible.js\"></script>\n\nhome:\n  links:\n  - text: Learn more at R4DS\n    href: http://r4ds.hadley.nz/strings.html\n\nreference:\n- title: Pattern matching\n\n- subtitle: String\n  contents:\n  - str_count\n  - str_detect\n  - str_escape\n  - str_extract\n  - str_locate\n  - str_match\n  - str_replace\n  - str_remove\n  - str_split\n  - str_starts\n  - modifiers\n\n- subtitle: Vector\n  desc: >\n    Unlike other pattern matching functions, these functions operate on the\n    original character vector, not the individual matches.\n  contents:\n  - str_subset\n  - str_which\n\n- title: Combining strings\n  contents:\n  - str_c\n  - str_flatten\n  - str_glue\n\n- title: Character based\n  contents:\n  - str_dup\n  - str_length\n  - str_pad\n  - str_sub\n  - str_trim\n  - str_trunc\n  - str_wrap\n\n- title: Locale aware\n  contents:\n  - str_order\n  - str_equal\n  - case\n  - str_unique\n\n- title: Other helpers\n  contents:\n  - invert_match\n  - str_conv\n  - str_like\n  - str_replace_na\n  - str_to_camel\n  - str_view\n  - word\n\n- title: Bundled data\n  contents:\n  - \"`stringr-data`\"\n\nnews:\n  releases:\n  - text: \"Version 1.6.0\"\n    href: https://tidyverse.org/blog/2025/11/stringr-1-6-0/\n  - text: \"Version 1.5.0\"\n    href: https://www.tidyverse.org/blog/2022/12/stringr-1-5-0/\n  - text: \"Version 1.4.0\"\n    href: https://www.tidyverse.org/articles/2019/02/stringr-1-4-0/\n  - text: \"Version 1.3.0\"\n    href: https://www.tidyverse.org/articles/2018/02/stringr-1-3-0/\n  - text: \"Version 1.2.0\"\n    href: https://blog.rstudio.com/2017/04/12/tidyverse-updates/\n  - text: \"Version 1.1.0\"\n    href: https://blog.rstudio.com/2016/08/24/stringr-1-1-0/\n  - text: \"Version 1.0.0\"\n    href: https://blog.rstudio.com/2015/05/05/stringr-1-0-0/\n"
  },
  {
    "path": "air.toml",
    "content": ""
  },
  {
    "path": "codecov.yml",
    "content": "comment: false\n\ncoverage:\n  status:\n    project:\n      default:\n        target: auto\n        threshold: 1%\n        informational: true\n    patch:\n      default:\n        target: auto\n        threshold: 1%\n        informational: true\n"
  },
  {
    "path": "cran-comments.md",
    "content": "## R CMD check results\n\n0 errors | 0 warnings | 0 note\n\n## revdepcheck results\n\nWe checked 2390 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package.\n\n * We saw 9 new problems\n * We failed to check 2 packages\n\nWe've been working with maintainers for over a month to get fixes to CRAN in a timely manner. You can track our efforts at <https://github.com/tidyverse/stringr/issues/590>.\n"
  },
  {
    "path": "data-raw/harvard-sentences.txt",
    "content": "The birch canoe slid on the smooth planks.\nGlue the sheet to the dark blue background.\nIt's easy to tell the depth of a well.\nThese days a chicken leg is a rare dish.\nRice is often served in round bowls.\nThe juice of lemons makes fine punch.\nThe box was thrown beside the parked truck.\nThe hogs were fed chopped corn and garbage.\nFour hours of steady work faced us.\nA large size in stockings is hard to sell.\nThe boy was there when the sun rose.\nA rod is used to catch pink salmon.\nThe source of the huge river is the clear spring.\nKick the ball straight and follow through.\nHelp the woman get back to her feet.\nA pot of tea helps to pass the evening.\nSmoky fires lack flame and heat.\nThe soft cushion broke the man's fall.\nThe salt breeze came across from the sea.\nThe girl at the booth sold fifty bonds.\nThe small pup gnawed a hole in the sock.\nThe fish twisted and turned on the bent hook.\nPress the pants and sew a button on the vest.\nThe swan dive was far short of perfect.\nThe beauty of the view stunned the young boy.\nTwo blue fish swam in the tank.\nHer purse was full of useless trash.\nThe colt reared and threw the tall rider.\nIt snowed, rained, and hailed the same morning.\nRead verse out loud for pleasure.\nHoist the load to your left shoulder.\nTake the winding path to reach the lake.\nNote closely the size of the gas tank.\nWipe the grease off his dirty face.\nMend the coat before you go out.\nThe wrist was badly strained and hung limp.\nThe stray cat gave birth to kittens.\nThe young girl gave no clear response.\nThe meal was cooked before the bell rang.\nWhat joy there is in living.\nA king ruled the state in the early days.\nThe ship was torn apart on the sharp reef.\nSickness kept him home the third week.\nThe wide road shimmered in the hot sun.\nThe lazy cow lay in the cool grass.\nLift the square stone over the fence.\nThe rope will bind the seven books at once.\nHop over the fence and plunge in.\nThe friendly gang left the drug store.\nMesh wire keeps chicks inside.\nThe frosty air passed through the coat.\nThe crooked maze failed to fool the mouse.\nAdding fast leads to wrong sums.\nThe show was a flop from the very start.\nA saw is a tool used for making boards.\nThe wagon moved on well oiled wheels.\nMarch the soldiers past the next hill.\nA cup of sugar makes sweet fudge.\nPlace a rosebush near the porch steps.\nBoth lost their lives in the raging storm.\nWe talked of the side show in the circus.\nUse a pencil to write the first draft.\nHe ran half way to the hardware store.\nThe clock struck to mark the third period.\nA small creek cut across the field.\nCars and busses stalled in snow drifts.\nThe set of china hit the floor with a crash.\nThis is a grand season for hikes on the road.\nThe dune rose from the edge of the water.\nThose words were the cue for the actor to leave.\nA yacht slid around the point into the bay.\nThe two met while playing on the sand.\nThe ink stain dried on the finished page.\nThe walled town was seized without a fight.\nThe lease ran out in sixteen weeks.\nA tame squirrel makes a nice pet.\nThe horn of the car woke the sleeping cop.\nThe heart beat strongly and with firm strokes.\nThe pearl was worn in a thin silver ring.\nThe fruit peel was cut in thick slices.\nThe Navy attacked the big task force.\nSee the cat glaring at the scared mouse.\nThere are more than two factors here.\nThe hat brim was wide and too droopy.\nThe lawyer tried to lose his case.\nThe grass curled around the fence post.\nCut the pie into large parts.\nMen strive but seldom get rich.\nAlways close the barn door tight.\nHe lay prone and hardly moved a limb.\nThe slush lay deep along the street.\nA wisp of cloud hung in the blue air.\nA pound of sugar costs more than eggs.\nThe fin was sharp and cut the clear water.\nThe play seems dull and quite stupid.\nBail the boat to stop it from sinking.\nThe term ended in late june that year.\nA Tusk is used to make costly gifts.\nTen pins were set in order.\nThe bill was paid every third week.\nOak is strong and also gives shade.\nCats and Dogs each hate the other.\nThe pipe began to rust while new.\nOpen the crate but don't break the glass.\nAdd the sum to the product of these three.\nThieves who rob friends deserve jail.\nThe ripe taste of cheese improves with age.\nAct on these orders with great speed.\nThe hog crawled under the high fence.\nMove the vat over the hot fire.\nThe bark of the pine tree was shiny and dark.\nLeaves turn brown and yellow in the fall.\nThe pennant waved when the wind blew.\nSplit the log with a quick, sharp blow.\nBurn peat after the logs give out.\nHe ordered peach pie with ice cream.\nWeave the carpet on the right hand side.\nHemp is a weed found in parts of the tropics.\nA lame back kept his score low.\nWe find joy in the simplest things.\nType out three lists of orders.\nThe harder he tried the less he got done.\nThe boss ran the show with a watchful eye.\nThe cup cracked and spilled its contents.\nPaste can cleanse the most dirty brass.\nThe slang word for raw whiskey is booze.\nIt caught its hind paw in a rusty trap.\nThe wharf could be seen at the farther shore.\nFeel the heat of the weak dying flame.\nThe tiny girl took off her hat.\nA cramp is no small danger on a swim.\nHe said the same phrase thirty times.\nPluck the bright rose without leaves.\nTwo plus seven is less than ten.\nThe glow deepened in the eyes of the sweet girl.\nBring your problems to the wise chief.\nWrite a fond note to the friend you cherish.\nClothes and lodging are free to new men.\nWe frown when events take a bad turn.\nPort is a strong wine with a smoky taste.\nThe young kid jumped the rusty gate.\nGuess the result from the first scores.\nA salt pickle tastes fine with ham.\nThe just claim got the right verdict.\nThose thistles bend in a high wind.\nPure bred poodles have curls.\nThe tree top waved in a graceful way.\nThe spot on the blotter was made by green ink.\nMud was spattered on the front of his white shirt.\nThe cigar burned a hole in the desk top.\nThe empty flask stood on the tin tray.\nA speedy man can beat this track mark.\nHe broke a new shoelace that day.\nThe coffee stand is too high for the couch.\nThe urge to write short stories is rare.\nThe pencils have all been used.\nThe pirates seized the crew of the lost ship.\nWe tried to replace the coin but failed.\nShe sewed the torn coat quite neatly.\nThe sofa cushion is red and of light weight.\nThe jacket hung on the back of the wide chair.\nAt that high level the air is pure.\nDrop the two when you add the figures.\nA filing case is now hard to buy.\nAn abrupt start does not win the prize.\nWood is best for making toys and blocks.\nThe office paint was a dull, sad tan.\nHe knew the skill of the great young actress.\nA rag will soak up spilled water.\nA shower of dirt fell from the hot pipes.\nSteam hissed from the broken valve.\nThe child almost hurt the small dog.\nThere was a sound of dry leaves outside.\nThe sky that morning was clear and bright blue.\nTorn scraps littered the stone floor.\nSunday is the best part of the week.\nThe doctor cured him with these pills.\nThe new girl was fired today at noon.\nThey felt gay when the ship arrived in port.\nAdd the store's account to the last cent.\nAcid burns holes in wool cloth.\nFairy tales should be fun to write.\nEight miles of woodland burned to waste.\nThe third act was dull and tired the players.\nA young child should not suffer fright.\nAdd the column and put the sum here.\nWe admire and love a good cook.\nThere the flood mark is ten inches.\nHe carved a head from the round block of marble.\nShe has a smart way of wearing clothes.\nThe fruit of a fig tree is apple shaped.\nCorn cobs can be used to kindle a fire.\nWhere were they when the noise started.\nThe paper box is full of thumb tacks.\nSell your gift to a buyer at a good gain.\nThe tongs lay beside the ice pail.\nThe petals fall with the next puff of wind.\nBring your best compass to the third class.\nThey could laugh although they were sad.\nFarmers came in to thresh the oat crop.\nThe brown house was on fire to the attic.\nThe lure is used to catch trout and flounder.\nFloat the soap on top of the bath water.\nA blue crane is a tall wading bird.\nA fresh start will work such wonders.\nThe club rented the rink for the fifth night.\nAfter the dance, they went straight home.\nThe hostess taught the new maid to serve.\nHe wrote his last novel there at the inn.\nEven the worst will beat his low score.\nThe cement had dried when he moved it.\nThe loss of the second ship was hard to take.\nThe fly made its way along the wall.\nDo that with a wooden stick.\nLive wires should be kept covered.\nThe large house had hot water taps.\nIt is hard to erase blue or red ink.\nWrite at once or you may forget it.\nThe doorknob was made of bright clean brass.\nThe wreck occurred by the bank on Main Street.\nA pencil with black lead writes best.\nCoax a young calf to drink from a bucket.\nSchools for ladies teach charm and grace.\nThe lamp shone with a steady green flame.\nThey took the axe and the saw to the forest.\nThe ancient coin was quite dull and worn.\nThe shaky barn fell with a loud crash.\nJazz and swing fans like fast music.\nRake the rubbish up and then burn it.\nSlash the gold cloth into fine ribbons.\nTry to have the court decide the case.\nThey are pushed back each time they attack.\nHe broke his ties with groups of former friends.\nThey floated on the raft to sun their white backs.\nThe map had an X that meant nothing.\nWhitings are small fish caught in nets.\nSome ads serve to cheat buyers.\nJerk the rope and the bell rings weakly.\nA waxed floor makes us lose balance.\nMadam, this is the best brand of corn.\nOn the islands the sea breeze is soft and mild.\nThe play began as soon as we sat down.\nThis will lead the world to more sound and fury.\nAdd salt before you fry the egg.\nThe rush for funds reached its peak Tuesday.\nThe birch looked stark white and lonesome.\nThe box is held by a bright red snapper.\nTo make pure ice, you freeze water.\nThe first worm gets snapped early.\nJump the fence and hurry up the bank.\nYell and clap as the curtain slides back.\nThey are men who walk the middle of the road.\nBoth brothers wear the same size.\nIn some form or other we need fun.\nThe prince ordered his head chopped off.\nThe houses are built of red clay bricks.\nDucks fly north but lack a compass.\nFruit flavors are used in fizz drinks.\nThese pills do less good than others.\nCanned pears lack full flavor.\nThe dark pot hung in the front closet.\nCarry the pail to the wall and spill it there.\nThe train brought our hero to the big town.\nWe are sure that one war is enough.\nGray paint stretched for miles around.\nThe rude laugh filled the empty room.\nHigh seats are best for football fans.\nTea served from the brown jug is tasty.\nA dash of pepper spoils beef stew.\nA zestful food is the hot-cross bun.\nThe horse trotted around the field at a brisk pace.\nFind the twin who stole the pearl necklace.\nCut the cord that binds the box tightly.\nThe red tape bound the smuggled food.\nLook in the corner to find the tan shirt.\nThe cold drizzle will halt the bond drive.\nNine men were hired to dig the ruins.\nThe junk yard had a mouldy smell.\nThe flint sputtered and lit a pine torch.\nSoak the cloth and drown the sharp odor.\nThe shelves were bare of both jam or crackers.\nA joy to every child is the swan boat.\nAll sat frozen and watched the screen.\nA cloud of dust stung his tender eyes.\nTo reach the end he needs much courage.\nShape the clay gently into block form.\nA ridge on a smooth surface is a bump or flaw.\nHedge apples may stain your hands green.\nQuench your thirst, then eat the crackers.\nTight curls get limp on rainy days.\nThe mute muffled the high tones of the horn.\nThe gold ring fits only a pierced ear.\nThe old pan was covered with hard fudge.\nWatch the log float in the wide river.\nThe node on the stalk of wheat grew daily.\nThe heap of fallen leaves was set on fire.\nWrite fast if you want to finish early.\nHis shirt was clean but one button was gone.\nThe barrel of beer was a brew of malt and hops.\nTin cans are absent from store shelves.\nSlide the box into that empty space.\nThe plant grew large and green in the window.\nThe beam dropped down on the workman's head.\nPink clouds floated with the breeze.\nShe danced like a swan, tall and graceful.\nThe tube was blown and the tire flat and useless.\nIt is late morning on the old wall clock.\nLet's all join as we sing the last chorus.\nThe last switch cannot be turned off.\nThe fight will end in just six minutes.\nThe store walls were lined with colored frocks.\nThe peace league met to discuss their plans.\nThe rise to fame of a person takes luck.\nPaper is scarce, so write with much care.\nThe quick fox jumped on the sleeping cat.\nThe nozzle of the fire hose was bright brass.\nScrew the round cap on as tight as needed.\nTime brings us many changes.\nThe purple tie was ten years old.\nMen think and plan and sometimes act.\nFill the ink jar with sticky glue.\nHe smoke a big pipe with strong contents.\nWe need grain to keep our mules healthy.\nPack the records in a neat thin case.\nThe crunch of feet in the snow was the only sound.\nThe copper bowl shone in the sun's rays.\nBoards will warp unless kept dry.\nThe plush chair leaned against the wall.\nGlass will clink when struck by metal.\nBathe and relax in the cool green grass.\nNine rows of soldiers stood in a line.\nThe beach is dry and shallow at low tide.\nThe idea is to sew both edges straight.\nThe kitten chased the dog down the street.\nPages bound in cloth make a book.\nTry to trace the fine lines of the painting.\nWomen form less than half of the group.\nThe zones merge in the central part of town.\nA gem in the rough needs work to polish.\nCode is used when secrets are sent.\nMost of the news is easy for us to hear.\nHe used the lathe to make brass objects.\nThe vane on top of the pole revolved in the wind.\nMince pie is a dish served to children.\nThe clan gathered on each dull night.\nLet it burn, it gives us warmth and comfort.\nA castle built from sand fails to endure.\nA child's wit saved the day for us.\nTack the strip of carpet to the worn floor.\nNext Tuesday we must vote.\nPour the stew from the pot into the plate.\nEach penny shone like new.\nThe man went to the woods to gather sticks.\nThe dirt piles were lines along the road.\nThe logs fell and tumbled into the clear stream.\nJust hoist it up and take it away.\nA ripe plum is fit for a king's palate.\nOur plans right now are hazy.\nBrass rings are sold by these natives.\nIt takes a good trap to capture a bear.\nFeed the white mouse some flower seeds.\nThe thaw came early and freed the stream.\nHe took the lead and kept it the whole distance.\nThe key you designed will fit the lock.\nPlead to the council to free the poor thief.\nBetter hash is made of rare beef.\nThis plank was made for walking on .\nThe lake sparkled in the red hot sun.\nHe crawled with care along the ledge.\nTend the sheep while the dog wanders.\nIt takes a lot of help to finish these.\nMark the spot with a sign painted red.\nTake two shares as a fair profit.\nThe fur of cats goes by many names.\nNorth winds bring colds and fevers.\nHe asks no person to vouch for him.\nGo now and come here later.\nA sash of gold silk will trim her dress.\nSoap can wash most dirt away.\nThat move means the game is over.\nHe wrote down a long list of items.\nA siege will crack the strong defense.\nGrape juice and water mix well.\nRoads are paved with sticky tar.\nFake stones shine but cost little.\nThe drip of the rain made a pleasant sound.\nSmoke poured out of every crack.\nServe the hot rum to the tired heroes.\nMuch of the story makes good sense.\nThe sun came up to light the eastern sky.\nHeave the line over the port side.\nA lathe cuts and trims any wood.\nIt's a dense crowd in two distinct ways.\nHis hip struck the knee of the next player.\nThe stale smell of old beer lingers.\nThe desk was firm on the shaky floor.\nIt takes heat to bring out the odor.\nBeef is scarcer than some lamb.\nRaise the sail and steer the ship northward.\nA cone costs five cents on Mondays.\nA pod is what peas always grow in.\nJerk that dart from the cork target.\nNo cement will hold hard wood.\nWe now have a new base for shipping.\nA list of names is carved around the base.\nThe sheep were led home by a dog.\nThree for a dime, the young peddler cried.\nThe sense of smell is better than that of touch.\nNo hardship seemed to make him sad.\nGrace makes up for lack of beauty.\nNudge gently but wake her now.\nThe news struck doubt into restless minds.\nOnce we stood beside the shore.\nA chink in the wall allowed a draft to blow.\nFasten two pins on each side.\nA cold dip restores health and zest.\nHe takes the oath of office each March.\nThe sand drifts over the sills of the old house.\nThe point of the steel pen was bent and twisted.\nThere is a lag between thought and act.\nSeed is needed to plant the spring corn.\nDraw the chart with heavy black lines.\nThe boy owed his pal thirty cents.\nThe chap slipped into the crowd and was lost.\nHats are worn to tea and not to dinner.\nThe ramp led up to the wide highway.\nBeat the dust from the rug onto the lawn.\nSay it slowly but make it ring clear.\nThe straw nest housed five robins.\nScreen the porch with woven straw mats.\nThis horse will nose his way to the finish.\nThe dry wax protects the deep scratch.\nHe picked up the dice for a second roll.\nThese coins will be needed to pay his debt.\nThe nag pulled the frail cart along.\nTwist the valve and release hot steam.\nThe vamp of the shoe had a gold buckle.\nThe smell of burned rags itches my nose.\nNew pants lack cuffs and pockets.\nThe marsh will freeze when cold enough.\nThey slice the sausage thin with a knife.\nThe bloom of the rose lasts a few days.\nA gray mare walked before the colt.\nBreakfast buns are fine with a hot drink.\nBottles hold four kinds of rum.\nThe man wore a feather in his felt hat.\nHe wheeled the bike past the winding road.\nDrop the ashes on the worn old rug.\nThe desk and both chairs were painted tan.\nThrow out the used paper cup and plate.\nA clean neck means a neat collar.\nThe couch cover and hall drapes were blue.\nThe stems of the tall glasses cracked and broke.\nThe wall phone rang loud and often.\nThe clothes dried on a thin wooden rack.\nTurn out the lantern which gives us light.\nThe cleat sank deeply into the soft turf.\nThe bills were mailed promptly on the tenth of the month.\nTo have is better than to wait and hope.\nThe price is fair for a good antique clock.\nThe music played on while they talked.\nDispense with a vest on a day like this.\nThe bunch of grapes was pressed into wine.\nHe sent the figs, but kept the ripe cherries.\nThe hinge on the door creaked with old age.\nThe screen before the fire kept in the sparks.\nFly by night and you waste little time.\nThick glasses helped him read the print.\nBirth and death marks the limits of life.\nThe chair looked strong but had no bottom.\nThe kite flew wildly in the high wind.\nA fur muff is stylish once more.\nThe tin box held priceless stones.\nWe need an end of all such matter.\nThe case was puzzling to the old and wise.\nThe bright lanterns were gay on the dark lawn.\nWe don't get much money but we have fun.\nThe youth drove with zest, but little skill.\nFive years he lived with a shaggy dog.\nA fence cuts through the corner lot.\nThe way to save money is not to spend much.\nShut the hatch before the waves push it in.\nThe odor of spring makes young hearts jump.\nCrack the walnut with your sharp side teeth.\nHe offered proof in the form of a large chart.\nSend the stuff in a thick paper bag.\nA quart of milk is water for the most part.\nThey told wild tales to frighten him.\nThe three story house was built of stone.\nIn the rear of the ground floor was a large passage.\nA man in a blue sweater sat at the desk.\nOats are a food eaten by horse and man.\nTheir eyelids droop for want of sleep.\nA sip of tea revives his tired friend.\nThere are many ways to do these things.\nTuck the sheet under the edge of the mat.\nA force equal to that would move the earth.\nWe like to see clear weather.\nThe work of the tailor is seen on each side.\nTake a chance and win a china doll.\nShake the dust from your shoes, stranger.\nShe was kind to sick old people.\nThe square wooden crate was packed to be shipped.\nThe dusty bench stood by the stone wall.\nWe dress to suit the weather of most days.\nSmile when you say nasty words.\nA bowl of rice is free with chicken stew.\nThe water in this well is a source of good health.\nTake shelter in this tent, but keep still.\nThat guy is the writer of a few banned books.\nThe little tales they tell are false.\nThe door was barred, locked, and bolted as well.\nRipe pears are fit for a queen's table.\nA big wet stain was on the round carpet.\nThe kite dipped and swayed, but stayed aloft.\nThe pleasant hours fly by much too soon.\nThe room was crowded with a wild mob.\nThis strong arm shall shield your honor.\nShe blushed when he gave her a white orchid.\nThe beetle droned in the hot June sun.\nPress the pedal with your left foot.\nNeat plans fail without luck.\nThe black trunk fell from the landing.\nThe bank pressed for payment of the debt.\nThe theft of the pearl pin was kept secret.\nShake hands with this friendly child.\nThe vast space stretched into the far distance.\nA rich farm is rare in this sandy waste.\nHis wide grin earned many friends.\nFlax makes a fine brand of paper.\nHurdle the pit with the aid of a long pole.\nA strong bid may scare your partner stiff.\nEven a just cause needs power to win.\nPeep under the tent and see the clowns.\nThe leaf drifts along with a slow spin.\nCheap clothes are flashy but don't last.\nA thing of small note can cause despair.\nFlood the mails with requests for this book.\nA thick coat of black paint covered all.\nThe pencil was cut to be sharp at both ends.\nThose last words were a strong statement.\nHe wrote his name boldly at the top of the sheet.\nDill pickles are sour but taste fine.\nDown that road is the way to the grain farmer.\nEither mud or dust are found at all times.\nThe best method is to fix it in place with clips.\nIf you mumble your speech will be lost.\nAt night the alarm roused him from a deep sleep.\nRead just what the meter says.\nFill your pack with bright trinkets for the poor.\nThe small red neon lamp went out.\nClams are small, round, soft, and tasty.\nThe fan whirled its round blades softly.\nThe line where the edges join was clean.\nBreathe deep and smell the piny air.\nIt matters not if he reads these words or those.\nA brown leather bag hung from its strap.\nA toad and a frog are hard to tell apart.\nA white silk jacket goes with any shoes.\nA break in the dam almost caused a flood.\nPaint the sockets in the wall dull green.\nThe child crawled into the dense grass.\nBribes fail where honest men work.\nTrample the spark, else the flames will spread.\nThe hilt of the sword was carved with fine designs.\nA round hole was drilled through the thin board.\nFootprints showed the path he took up the beach.\nShe was waiting at my front lawn.\nA vent near the edge brought in fresh air.\nProd the old mule with a crooked stick.\nIt is a band of steel three inches wide.\nThe pipe ran almost the length of the ditch.\nIt was hidden from sight by a mass of leaves and shrubs.\nThe weight of the package was seen on the high scale.\nWake and rise, and step into the green outdoors.\nThe green light in the brown box flickered.\nThe brass tube circled the high wall.\nThe lobes of her ears were pierced to hold rings.\nHold the hammer near the end to drive the nail.\nNext Sunday is the twelfth of the month.\nEvery word and phrase he speaks is true.\nHe put his last cartridge into the gun and fired.\nThey took their kids from the public school.\nDrive the screw straight into the wood.\nKeep the hatch tight and the watch constant.\nSever the twine with a quick snip of the knife.\nPaper will dry out when wet.\nSlide the catch back and open the desk.\nHelp the weak to preserve their strength.\nA sullen smile gets few friends.\nStop whistling and watch the boys march.\nJerk the cord, and out tumbles the gold.\nSlide the tray across the glass top.\nThe cloud moved in a stately way and was gone.\nLight maple makes for a swell room.\nSet the piece here and say nothing.\nDull stories make her laugh.\nA stiff cord will do to fasten your shoe.\nGet the trust fund to the bank early.\nChoose between the high road and the low.\nA plea for funds seems to come again.\nHe lent his coat to the tall gaunt stranger.\nThere is a strong chance it will happen once more.\nThe duke left the park in a silver coach.\nGreet the new guests and leave quickly.\nWhen the frost has come it is time for turkey.\nSweet words work better than fierce.\nA thin stripe runs down the middle.\nA six comes up more often than a ten.\nLush ferns grow on the lofty rocks.\nThe ram scared the school children off.\nThe team with the best timing looks good.\nThe farmer swapped his horse for a brown ox.\nSit on the perch and tell the others what to do.\nA steep trail is painful for our feet.\nThe early phase of life moves fast.\nGreen moss grows on the northern side.\nTea in thin china has a sweet taste.\nPitch the straw through the door of the stable.\nThe latch on the back gate needed a nail.\nThe goose was brought straight from the old market.\nThe sink is the thing in which we pile dishes.\nA whiff of it will cure the most stubborn cold.\nThe facts don't always show who is right.\nShe flaps her cape as she parades the street.\nThe loss of the cruiser was a blow to the fleet.\nLoop the braid to the left and then over.\nPlead with the lawyer to drop the lost cause.\nCalves thrive on tender spring grass.\nPost no bills on this office wall.\nTear a thin sheet from the yellow pad.\nA cruise in warm waters in a sleek yacht is fun.\nA streak of color ran down the left edge.\nIt was done before the boy could see it.\nCrouch before you jump or miss the mark.\nPack the kits and don't forget the salt.\nThe square peg will settle in the round hole.\nFine soap saves tender skin.\nPoached eggs and tea must suffice.\nBad nerves are jangled by a door slam.\nShip maps are different from those for planes.\nDimes showered down from all sides.\nThey sang the same tunes at each party.\nThe sky in the west is tinged with orange red.\nThe pods of peas ferment in bare fields.\nThe horse balked and threw the tall rider.\nThe hitch between the horse and cart broke.\nPile the coal high in the shed corner.\nA gold vase is both rare and costly.\nThe knife was hung inside its bright sheath.\nThe rarest spice comes from the far East.\nThe roof should be tilted at a sharp slant.\nA smatter of French is worse than none.\nThe mule trod the treadmill day and night.\nThe aim of the contest is to raise a great fund.\nTo send it now in large amounts is bad.\nThere is a fine hard tang in salty air.\nCod is the main business of the north shore.\nThe slab was hewn from heavy blocks of slate.\nDunk the stale biscuits into strong drink.\nHang tinsel from both branches.\nCap the jar with a tight brass cover.\nThe poor boy missed the boat again.\nBe sure to set that lamp firmly in the hole.\nPick a card and slip it under the pack.\nA round mat will cover the dull spot.\nThe first part of the plan needs changing.\nA good book informs of what we ought to know.\nThe mail comes in three batches per day.\nYou cannot brew tea in a cold pot.\nDots of light betrayed the black cat.\nPut the chart on the mantel and tack it down.\nThe night shift men rate extra pay.\nThe red paper brightened the dim stage.\nSee the player scoot to third base.\nSlide the bill between the two leaves.\nMany hands help get the job done.\nWe don't like to admit our small faults.\nNo doubt about the way the wind blows.\nDig deep in the earth for pirate's gold.\nThe steady drip is worse than a drenching rain.\nA flat pack takes less luggage space.\nGreen ice frosted the punch bowl.\nA stuffed chair slipped from the moving van.\nThe stitch will serve but needs to be shortened.\nA thin book fits in the side pocket.\nThe gloss on top made it unfit to read.\nThe hail pattered on the burnt brown grass.\nSeven seals were stamped on great sheets.\nOur troops are set to strike heavy blows.\nThe store was jammed before the sale could start.\nIt was a bad error on the part of the new judge.\nOne step more and the board will collapse.\nTake the match and strike it against your shoe.\nThe pot boiled but the contents failed to jell.\nThe baby puts his right foot in his mouth.\nThe bombs left most of the town in ruins.\nStop and stare at the hard working man.\nThe streets are narrow and full of sharp turns.\nThe pup jerked the leash as he saw a feline shape.\nOpen your book to the first page.\nFish evade the net and swim off.\nDip the pail once and let it settle.\nWill you please answer that phone.\nThe big red apple fell to the ground.\nThe curtain rose and the show was on.\nThe young prince became heir to the throne.\nHe sent the boy on a short errand.\nLeave now and you will arrive on time.\nThe corner store was robbed last night.\nA gold ring will please most any girl.\nThe long journey home took a year.\nShe saw a cat in the neighbor's house.\nA pink shell was found on the sandy beach.\nSmall children came to see him.\nThe grass and bushes were wet with dew.\nThe blind man counted his old coins.\nA severe storm tore down the barn.\nShe called his name many times.\nWhen you hear the bell, come quickly.\n"
  },
  {
    "path": "data-raw/samples.R",
    "content": "words <- rcorpora::corpora(\"words/common\")$commonWords\nfruit <- rcorpora::corpora(\"foods/fruits\")$fruits\n\nhtml <- read_html(\"https://harvardsentences.com\")\nhtml %>%\n  html_elements(\"li\") %>%\n  html_text() %>%\n  iconv(to = \"ASCII//translit\") %>%\n  writeLines(\"data-raw/harvard-sentences.txt\")\nsentences <- readr::read_lines(\"data-raw/harvard-sentences.txt\")\n\nusethis::use_data(words, overwrite = TRUE)\nusethis::use_data(fruit, overwrite = TRUE)\nusethis::use_data(sentences, overwrite = TRUE)\n"
  },
  {
    "path": "inst/htmlwidgets/lib/str_view.css",
    "content": ".str_view ul {\n  font-size: 16px;\n}\n\n.str_view ul, .str_view li {\n  list-style: none;\n  padding: 0;\n  margin: 0.5em 0;\n}\n\n.str_view .match {\n  border: 1px solid #ccc;\n  background-color: #eee;\n  border-color: #ccc;\n  border-radius: 3px;\n}\n\n.str_view .special {\n  background-color: red;\n}\n"
  },
  {
    "path": "inst/htmlwidgets/str_view.js",
    "content": "HTMLWidgets.widget({\n\n  name: 'str_view',\n\n  type: 'output',\n\n  initialize: function(el, width, height) {\n  },\n\n  renderValue: function(el, x, instance) {\n    el.innerHTML = x.html;\n  },\n\n  resize: function(el, width, height, instance) {\n  }\n\n});\n"
  },
  {
    "path": "inst/htmlwidgets/str_view.yaml",
    "content": "dependencies:\n - name: str_view\n   version: 0.1.0\n   src: htmlwidgets/lib/\n   stylesheet: str_view.css\n"
  },
  {
    "path": "man/case.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/case.R\n\\name{case}\n\\alias{case}\n\\alias{str_to_upper}\n\\alias{str_to_lower}\n\\alias{str_to_title}\n\\alias{str_to_sentence}\n\\title{Convert string to upper case, lower case, title case, or sentence case}\n\\usage{\nstr_to_upper(string, locale = \"en\")\n\nstr_to_lower(string, locale = \"en\")\n\nstr_to_title(string, locale = \"en\")\n\nstr_to_sentence(string, locale = \"en\")\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{locale}{Locale to use for comparisons. See\n\\code{\\link[stringi:stri_locale_list]{stringi::stri_locale_list()}} for all possible options.\nDefaults to \"en\" (English) to ensure that default behaviour is\nconsistent across platforms.}\n}\n\\value{\nA character vector the same length as \\code{string}.\n}\n\\description{\n\\itemize{\n\\item \\code{str_to_upper()} converts to upper case.\n\\item \\code{str_to_lower()} converts to lower case.\n\\item \\code{str_to_title()} converts to title case, where only the first letter of\neach word is capitalized.\n\\item \\code{str_to_sentence()} convert to sentence case, where only the first letter\nof sentence is capitalized.\n}\n}\n\\examples{\ndog <- \"The quick brown dog\"\nstr_to_upper(dog)\nstr_to_lower(dog)\nstr_to_title(dog)\nstr_to_sentence(\"the quick brown dog\")\n\n# Locale matters!\nstr_to_upper(\"i\") # English\nstr_to_upper(\"i\", \"tr\") # Turkish\n}\n"
  },
  {
    "path": "man/invert_match.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/locate.R\n\\name{invert_match}\n\\alias{invert_match}\n\\title{Switch location of matches to location of non-matches}\n\\usage{\ninvert_match(loc)\n}\n\\arguments{\n\\item{loc}{matrix of match locations, as from \\code{\\link[=str_locate_all]{str_locate_all()}}}\n}\n\\value{\nnumeric match giving locations of non-matches\n}\n\\description{\nInvert a matrix of match locations to match the opposite of what was\npreviously matched.\n}\n\\examples{\nnumbers <- \"1 and 2 and 4 and 456\"\nnum_loc <- str_locate_all(numbers, \"[0-9]+\")[[1]]\nstr_sub(numbers, num_loc[, \"start\"], num_loc[, \"end\"])\n\ntext_loc <- invert_match(num_loc)\nstr_sub(numbers, text_loc[, \"start\"], text_loc[, \"end\"])\n}\n"
  },
  {
    "path": "man/modifiers.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/modifiers.R\n\\name{modifiers}\n\\alias{modifiers}\n\\alias{fixed}\n\\alias{coll}\n\\alias{regex}\n\\alias{boundary}\n\\title{Control matching behaviour with modifier functions}\n\\usage{\nfixed(pattern, ignore_case = FALSE)\n\ncoll(pattern, ignore_case = FALSE, locale = \"en\", ...)\n\nregex(\n  pattern,\n  ignore_case = FALSE,\n  multiline = FALSE,\n  comments = FALSE,\n  dotall = FALSE,\n  ...\n)\n\nboundary(\n  type = c(\"character\", \"line_break\", \"sentence\", \"word\"),\n  skip_word_none = NA,\n  ...\n)\n}\n\\arguments{\n\\item{pattern}{Pattern to modify behaviour.}\n\n\\item{ignore_case}{Should case differences be ignored in the match?\nFor \\code{fixed()}, this uses a simple algorithm which assumes a\none-to-one mapping between upper and lower case letters.}\n\n\\item{locale}{Locale to use for comparisons. See\n\\code{\\link[stringi:stri_locale_list]{stringi::stri_locale_list()}} for all possible options.\nDefaults to \"en\" (English) to ensure that default behaviour is\nconsistent across platforms.}\n\n\\item{...}{Other less frequently used arguments passed on to\n\\code{\\link[stringi:stri_opts_collator]{stringi::stri_opts_collator()}},\n\\code{\\link[stringi:stri_opts_regex]{stringi::stri_opts_regex()}}, or\n\\code{\\link[stringi:stri_opts_brkiter]{stringi::stri_opts_brkiter()}}}\n\n\\item{multiline}{If \\code{TRUE}, \\code{$} and \\code{^} match\nthe beginning and end of each line. If \\code{FALSE}, the\ndefault, only match the start and end of the input.}\n\n\\item{comments}{If \\code{TRUE}, white space and comments beginning with\n\\verb{#} are ignored. Escape literal spaces with \\verb{\\\\\\\\ }.}\n\n\\item{dotall}{If \\code{TRUE}, \\code{.} will also match line terminators.}\n\n\\item{type}{Boundary type to detect.\n\\describe{\n\\item{\\code{character}}{Every character is a boundary.}\n\\item{\\code{line_break}}{Boundaries are places where it is acceptable to have\na line break in the current locale.}\n\\item{\\code{sentence}}{The beginnings and ends of sentences are boundaries,\nusing intelligent rules to avoid counting abbreviations\n(\\href{https://www.unicode.org/reports/tr29/#Sentence_Boundaries}{details}).}\n\\item{\\code{word}}{The beginnings and ends of words are boundaries.}\n}}\n\n\\item{skip_word_none}{Ignore \"words\" that don't contain any characters\nor numbers - i.e. punctuation. Default \\code{NA} will skip such \"words\"\nonly when splitting on \\code{word} boundaries.}\n}\n\\value{\nA stringr modifier object, i.e. a character vector with\nparent S3 class \\code{stringr_pattern}.\n}\n\\description{\nModifier functions control the meaning of the \\code{pattern} argument to\nstringr functions:\n\\itemize{\n\\item \\code{boundary()}: Match boundaries between things.\n\\item \\code{coll()}: Compare strings using standard Unicode collation rules.\n\\item \\code{fixed()}: Compare literal bytes.\n\\item \\code{regex()} (the default): Uses ICU regular expressions.\n}\n}\n\\examples{\npattern <- \"a.b\"\nstrings <- c(\"abb\", \"a.b\")\nstr_detect(strings, pattern)\nstr_detect(strings, fixed(pattern))\nstr_detect(strings, coll(pattern))\n\n# coll() is useful for locale-aware case-insensitive matching\ni <- c(\"I\", \"\\u0130\", \"i\")\ni\nstr_detect(i, fixed(\"i\", TRUE))\nstr_detect(i, coll(\"i\", TRUE))\nstr_detect(i, coll(\"i\", TRUE, locale = \"tr\"))\n\n# Word boundaries\nwords <- c(\"These are   some words.\")\nstr_count(words, boundary(\"word\"))\nstr_split(words, \" \")[[1]]\nstr_split(words, boundary(\"word\"))[[1]]\n\n# Regular expression variations\nstr_extract_all(\"The Cat in the Hat\", \"[a-z]+\")\nstr_extract_all(\"The Cat in the Hat\", regex(\"[a-z]+\", TRUE))\n\nstr_extract_all(\"a\\nb\\nc\", \"^.\")\nstr_extract_all(\"a\\nb\\nc\", regex(\"^.\", multiline = TRUE))\n\nstr_extract_all(\"a\\nb\\nc\", \"a.\")\nstr_extract_all(\"a\\nb\\nc\", regex(\"a.\", dotall = TRUE))\n}\n"
  },
  {
    "path": "man/pipe.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/utils.R\n\\name{\\%>\\%}\n\\alias{\\%>\\%}\n\\title{Pipe operator}\n\\usage{\nlhs \\%>\\% rhs\n}\n\\description{\nPipe operator\n}\n\\keyword{internal}\n"
  },
  {
    "path": "man/str_c.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/c.R\n\\name{str_c}\n\\alias{str_c}\n\\title{Join multiple strings into one string}\n\\usage{\nstr_c(..., sep = \"\", collapse = NULL)\n}\n\\arguments{\n\\item{...}{One or more character vectors.\n\n\\code{NULL}s are removed; scalar inputs (vectors of length 1) are recycled to\nthe common length of vector inputs.\n\nLike most other R functions, missing values are \"infectious\": whenever\na missing value is combined with another string the result will always\nbe missing. Use \\code{\\link[dplyr:coalesce]{dplyr::coalesce()}} or \\code{\\link[=str_replace_na]{str_replace_na()}} to convert to\nthe desired value.}\n\n\\item{sep}{String to insert between input vectors.}\n\n\\item{collapse}{Optional string used to combine output into single\nstring. Generally better to use \\code{\\link[=str_flatten]{str_flatten()}} if you needed this\nbehaviour.}\n}\n\\value{\nIf \\code{collapse = NULL} (the default) a character vector with\nlength equal to the longest input. If \\code{collapse} is a string, a character\nvector of length 1.\n}\n\\description{\n\\code{str_c()} combines multiple character vectors into a single character\nvector. It's very similar to \\code{\\link[=paste0]{paste0()}} but uses tidyverse recycling and\n\\code{NA} rules.\n\nOne way to understand how \\code{str_c()} works is picture a 2d matrix of strings,\nwhere each argument forms a column. \\code{sep} is inserted between each column,\nand then each row is combined together into a single string. If \\code{collapse}\nis set, it's inserted between each row, and then the result is again\ncombined, this time into a single string.\n}\n\\examples{\nstr_c(\"Letter: \", letters)\nstr_c(\"Letter\", letters, sep = \": \")\nstr_c(letters, \" is for\", \"...\")\nstr_c(letters[-26], \" comes before \", letters[-1])\n\nstr_c(letters, collapse = \"\")\nstr_c(letters, collapse = \", \")\n\n# Differences from paste() ----------------------\n# Missing inputs give missing outputs\nstr_c(c(\"a\", NA, \"b\"), \"-d\")\npaste0(c(\"a\", NA, \"b\"), \"-d\")\n# Use str_replace_NA to display literal NAs:\nstr_c(str_replace_na(c(\"a\", NA, \"b\")), \"-d\")\n\n# Uses tidyverse recycling rules\n\\dontrun{str_c(1:2, 1:3)} # errors\npaste0(1:2, 1:3)\n\nstr_c(\"x\", character())\npaste0(\"x\", character())\n}\n"
  },
  {
    "path": "man/str_conv.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/conv.R\n\\name{str_conv}\n\\alias{str_conv}\n\\title{Specify the encoding of a string}\n\\usage{\nstr_conv(string, encoding)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{encoding}{Name of encoding. See \\code{\\link[stringi:stri_enc_list]{stringi::stri_enc_list()}}\nfor a complete list.}\n}\n\\description{\nThis is a convenient way to override the current encoding of a string.\n}\n\\examples{\n# Example from encoding?stringi::stringi\nx <- rawToChar(as.raw(177))\nx\nstr_conv(x, \"ISO-8859-2\") # Polish \"a with ogonek\"\nstr_conv(x, \"ISO-8859-1\") # Plus-minus\n}\n"
  },
  {
    "path": "man/str_count.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/count.R\n\\name{str_count}\n\\alias{str_count}\n\\title{Count number of matches}\n\\usage{\nstr_count(string, pattern = \"\")\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nMatch character, word, line and sentence boundaries with\n\\code{\\link[=boundary]{boundary()}}. The empty string, \\verb{\"\"``, is equivalent to }boundary(\"character\")`.}\n}\n\\value{\nAn integer vector the same length as \\code{string}/\\code{pattern}.\n}\n\\description{\nCounts the number of times \\code{pattern} is found within each element\nof \\code{string.}\n}\n\\examples{\nfruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\nstr_count(fruit, \"a\")\nstr_count(fruit, \"p\")\nstr_count(fruit, \"e\")\nstr_count(fruit, c(\"a\", \"b\", \"p\", \"p\"))\n\nstr_count(c(\"a.\", \"...\", \".a.a\"), \".\")\nstr_count(c(\"a.\", \"...\", \".a.a\"), fixed(\".\"))\n}\n\\seealso{\n\\code{\\link[stringi:stri_count]{stringi::stri_count()}} which this function wraps.\n\n\\code{\\link[=str_locate]{str_locate()}}/\\code{\\link[=str_locate_all]{str_locate_all()}} to locate position\nof matches\n}\n"
  },
  {
    "path": "man/str_detect.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/detect.R\n\\name{str_detect}\n\\alias{str_detect}\n\\title{Detect the presence/absence of a match}\n\\usage{\nstr_detect(string, pattern, negate = FALSE)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nYou can not match boundaries, including \\code{\"\"}, with this function.}\n\n\\item{negate}{If \\code{TRUE}, inverts the resulting boolean vector.}\n}\n\\value{\nA logical vector the same length as \\code{string}/\\code{pattern}.\n}\n\\description{\n\\code{str_detect()} returns a logical vector with \\code{TRUE} for each element of\n\\code{string} that matches \\code{pattern} and \\code{FALSE} otherwise. It's equivalent to\n\\code{grepl(pattern, string)}.\n}\n\\examples{\nfruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\nstr_detect(fruit, \"a\")\nstr_detect(fruit, \"^a\")\nstr_detect(fruit, \"a$\")\nstr_detect(fruit, \"b\")\nstr_detect(fruit, \"[aeiou]\")\n\n# Also vectorised over pattern\nstr_detect(\"aecfg\", letters)\n\n# Returns TRUE if the pattern do NOT match\nstr_detect(fruit, \"^p\", negate = TRUE)\n}\n\\seealso{\n\\code{\\link[stringi:stri_detect]{stringi::stri_detect()}} which this function wraps,\n\\code{\\link[=str_subset]{str_subset()}} for a convenient wrapper around\n\\code{x[str_detect(x, pattern)]}\n}\n"
  },
  {
    "path": "man/str_dup.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/dup.R\n\\name{str_dup}\n\\alias{str_dup}\n\\title{Duplicate a string}\n\\usage{\nstr_dup(string, times, sep = NULL)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{times}{Number of times to duplicate each string.}\n\n\\item{sep}{String to insert between each duplicate.}\n}\n\\value{\nA character vector the same length as \\code{string}/\\code{times}.\n}\n\\description{\n\\code{str_dup()} duplicates the characters within a string, e.g.\n\\code{str_dup(\"xy\", 3)} returns \\code{\"xyxyxy\"}.\n}\n\\examples{\nfruit <- c(\"apple\", \"pear\", \"banana\")\nstr_dup(fruit, 2)\nstr_dup(fruit, 2, sep = \" \")\nstr_dup(fruit, 1:3)\nstr_c(\"ba\", str_dup(\"na\", 0:5))\n}\n"
  },
  {
    "path": "man/str_equal.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/equal.R\n\\name{str_equal}\n\\alias{str_equal}\n\\title{Determine if two strings are equivalent}\n\\usage{\nstr_equal(x, y, locale = \"en\", ignore_case = FALSE, ...)\n}\n\\arguments{\n\\item{x, y}{A pair of character vectors.}\n\n\\item{locale}{Locale to use for comparisons. See\n\\code{\\link[stringi:stri_locale_list]{stringi::stri_locale_list()}} for all possible options.\nDefaults to \"en\" (English) to ensure that default behaviour is\nconsistent across platforms.}\n\n\\item{ignore_case}{Ignore case when comparing strings?}\n\n\\item{...}{Other options used to control collation. Passed on to\n\\code{\\link[stringi:stri_opts_collator]{stringi::stri_opts_collator()}}.}\n}\n\\value{\nAn logical vector the same length as \\code{x}/\\code{y}.\n}\n\\description{\nThis uses Unicode canonicalisation rules, and optionally ignores case.\n}\n\\examples{\n# These two strings encode \"a\" with an accent in two different ways\na1 <- \"\\u00e1\"\na2 <- \"a\\u0301\"\nc(a1, a2)\n\na1 == a2\nstr_equal(a1, a2)\n\n# ohm and omega use different code points but should always be treated\n# as equal\nohm <- \"\\u2126\"\nomega <- \"\\u03A9\"\nc(ohm, omega)\n\nohm == omega\nstr_equal(ohm, omega)\n}\n\\seealso{\n\\code{\\link[stringi:stri_compare]{stringi::stri_cmp_equiv()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_escape.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/escape.R\n\\name{str_escape}\n\\alias{str_escape}\n\\title{Escape regular expression metacharacters}\n\\usage{\nstr_escape(string)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n}\n\\value{\nA character vector the same length as \\code{string}.\n}\n\\description{\nThis function escapes metacharacter, the characters that have special\nmeaning to the regular expression engine. In most cases you are better\noff using \\code{\\link[=fixed]{fixed()}} since it is faster, but \\code{str_escape()} is useful\nif you are composing user provided strings into a pattern.\n}\n\\examples{\nstr_detect(c(\"a\", \".\"), \".\")\nstr_detect(c(\"a\", \".\"), str_escape(\".\"))\n}\n"
  },
  {
    "path": "man/str_extract.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/extract.R\n\\name{str_extract}\n\\alias{str_extract}\n\\alias{str_extract_all}\n\\title{Extract the complete match}\n\\usage{\nstr_extract(string, pattern, group = NULL)\n\nstr_extract_all(string, pattern, simplify = FALSE)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nMatch character, word, line and sentence boundaries with\n\\code{\\link[=boundary]{boundary()}}. The empty string, \\verb{\"\"``, is equivalent to }boundary(\"character\")`.}\n\n\\item{group}{If supplied, instead of returning the complete match, will\nreturn the matched text from the specified capturing group.}\n\n\\item{simplify}{A boolean.\n\\itemize{\n\\item \\code{FALSE} (the default): returns a list of character vectors.\n\\item \\code{TRUE}: returns a character matrix.\n}}\n}\n\\value{\n\\itemize{\n\\item \\code{str_extract()}: an character vector the same length as \\code{string}/\\code{pattern}.\n\\item \\code{str_extract_all()}: a list of character vectors the same length as\n\\code{string}/\\code{pattern}.\n}\n}\n\\description{\n\\code{str_extract()} extracts the first complete match from each string,\n\\code{str_extract_all()}extracts all matches from each string.\n}\n\\examples{\nshopping_list <- c(\"apples x4\", \"bag of flour\", \"bag of sugar\", \"milk x2\")\nstr_extract(shopping_list, \"\\\\\\\\d\")\nstr_extract(shopping_list, \"[a-z]+\")\nstr_extract(shopping_list, \"[a-z]{1,4}\")\nstr_extract(shopping_list, \"\\\\\\\\b[a-z]{1,4}\\\\\\\\b\")\n\nstr_extract(shopping_list, \"([a-z]+) of ([a-z]+)\")\nstr_extract(shopping_list, \"([a-z]+) of ([a-z]+)\", group = 1)\nstr_extract(shopping_list, \"([a-z]+) of ([a-z]+)\", group = 2)\n\n# Extract all matches\nstr_extract_all(shopping_list, \"[a-z]+\")\nstr_extract_all(shopping_list, \"\\\\\\\\b[a-z]+\\\\\\\\b\")\nstr_extract_all(shopping_list, \"\\\\\\\\d\")\n\n# Simplify results into character matrix\nstr_extract_all(shopping_list, \"\\\\\\\\b[a-z]+\\\\\\\\b\", simplify = TRUE)\nstr_extract_all(shopping_list, \"\\\\\\\\d\", simplify = TRUE)\n\n# Extract all words\nstr_extract_all(\"This is, suprisingly, a sentence.\", boundary(\"word\"))\n}\n\\seealso{\n\\code{\\link[=str_match]{str_match()}} to extract matched groups;\n\\code{\\link[stringi:stri_extract]{stringi::stri_extract()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_flatten.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/flatten.R\n\\name{str_flatten}\n\\alias{str_flatten}\n\\alias{str_flatten_comma}\n\\title{Flatten a string}\n\\usage{\nstr_flatten(string, collapse = \"\", last = NULL, na.rm = FALSE)\n\nstr_flatten_comma(string, last = NULL, na.rm = FALSE)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{collapse}{String to insert between each piece. Defaults to \\code{\"\"}.}\n\n\\item{last}{Optional string to use in place of the final separator.}\n\n\\item{na.rm}{Remove missing values? If \\code{FALSE} (the default), the result\nwill be \\code{NA} if any element of \\code{string} is \\code{NA}.}\n}\n\\value{\nA string, i.e. a character vector of length 1.\n}\n\\description{\n\\code{str_flatten()} reduces a character vector to a single string. This is a\nsummary function because regardless of the length of the input \\code{x}, it\nalways returns a single string.\n\n\\code{str_flatten_comma()} is a variation designed specifically for flattening\nwith commas. It automatically recognises if \\code{last} uses the Oxford comma\nand handles the special case of 2 elements.\n}\n\\examples{\nstr_flatten(letters)\nstr_flatten(letters, \"-\")\n\nstr_flatten(letters[1:3], \", \")\n\n# Use last to customise the last component\nstr_flatten(letters[1:3], \", \", \" and \")\n\n# this almost works if you want an Oxford (aka serial) comma\nstr_flatten(letters[1:3], \", \", \", and \")\n\n# but it will always add a comma, even when not necessary\nstr_flatten(letters[1:2], \", \", \", and \")\n\n# str_flatten_comma knows how to handle the Oxford comma\nstr_flatten_comma(letters[1:3], \", and \")\nstr_flatten_comma(letters[1:2], \", and \")\n}\n"
  },
  {
    "path": "man/str_glue.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/glue.R\n\\name{str_glue}\n\\alias{str_glue}\n\\alias{str_glue_data}\n\\title{Interpolation with glue}\n\\usage{\nstr_glue(..., .sep = \"\", .envir = parent.frame(), .trim = TRUE)\n\nstr_glue_data(.x, ..., .sep = \"\", .envir = parent.frame(), .na = \"NA\")\n}\n\\arguments{\n\\item{...}{[\\code{expressions}]\\cr Unnamed arguments are taken to be expression\nstring(s) to format. Multiple inputs are concatenated together before formatting.\nNamed arguments are taken to be temporary variables available for substitution.\n\nFor \\code{glue_data()}, elements in \\code{...} override the values in \\code{.x}.}\n\n\\item{.sep}{[\\code{character(1)}: \\sQuote{\"\"}]\\cr Separator used to separate elements.}\n\n\\item{.envir}{[\\code{environment}: \\code{parent.frame()}]\\cr Environment to evaluate each expression in. Expressions are\nevaluated from left to right. If \\code{.x} is an environment, the expressions are\nevaluated in that environment and \\code{.envir} is ignored. If \\code{NULL} is passed, it is equivalent to \\code{\\link[=emptyenv]{emptyenv()}}.}\n\n\\item{.trim}{[\\code{logical(1)}: \\sQuote{TRUE}]\\cr Whether to trim the input\ntemplate with \\code{\\link[glue:trim]{trim()}} or not.}\n\n\\item{.x}{[\\code{listish}]\\cr An environment, list, or data frame used to lookup values.}\n\n\\item{.na}{[\\code{character(1)}: \\sQuote{NA}]\\cr Value to replace \\code{NA} values\nwith. If \\code{NULL} missing values are propagated, that is an \\code{NA} result will\ncause \\code{NA} output. Otherwise the value is replaced by the value of \\code{.na}.}\n}\n\\value{\nA character vector with same length as the longest input.\n}\n\\description{\nThese functions are wrappers around \\code{\\link[glue:glue]{glue::glue()}} and \\code{\\link[glue:glue]{glue::glue_data()}},\nwhich provide a powerful and elegant syntax for interpolating strings\nwith \\code{{}}.\n\nThese wrappers provide a small set of the full options. Use \\code{glue()} and\n\\code{glue_data()} directly from glue for more control.\n}\n\\examples{\nname <- \"Fred\"\nage <- 50\nanniversary <- as.Date(\"1991-10-12\")\nstr_glue(\n  \"My name is {name}, \",\n  \"my age next year is {age + 1}, \",\n  \"and my anniversary is {format(anniversary, '\\%A, \\%B \\%d, \\%Y')}.\"\n)\n\n# single braces can be inserted by doubling them\nstr_glue(\"My name is {name}, not {{name}}.\")\n\n# You can also used named arguments\nstr_glue(\n  \"My name is {name}, \",\n  \"and my age next year is {age + 1}.\",\n  name = \"Joe\",\n  age = 40\n)\n\n# `str_glue_data()` is useful in data pipelines\nmtcars \\%>\\% str_glue_data(\"{rownames(.)} has {hp} hp\")\n}\n"
  },
  {
    "path": "man/str_interp.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/interp.R\n\\name{str_interp}\n\\alias{str_interp}\n\\title{String interpolation}\n\\usage{\nstr_interp(string, env = parent.frame())\n}\n\\arguments{\n\\item{string}{A template character string. This function is not vectorised:\na character vector will be collapsed into a single string.}\n\n\\item{env}{The environment in which to evaluate the expressions.}\n}\n\\value{\nAn interpolated character string.\n}\n\\description{\n\\ifelse{html}{\\href{https://lifecycle.r-lib.org/articles/stages.html#superseded}{\\figure{lifecycle-superseded.svg}{options: alt='[Superseded]'}}}{\\strong{[Superseded]}}\n\n\\code{str_interp()} is superseded in favour of \\code{\\link[=str_glue]{str_glue()}}.\n\nString interpolation is a useful way of specifying a character string which\ndepends on values in a certain environment. It allows for string creation\nwhich is easier to read and write when compared to using e.g.\n\\code{\\link[=paste]{paste()}} or \\code{\\link[=sprintf]{sprintf()}}. The (template) string can\ninclude expression placeholders of the form \\verb{$\\{expression\\}} or\n\\verb{$[format]\\{expression\\}}, where expressions are valid R expressions that\ncan be evaluated in the given environment, and \\code{format} is a format\nspecification valid for use with \\code{\\link[=sprintf]{sprintf()}}.\n}\n\\examples{\n\n# Using values from the environment, and some formats\nuser_name <- \"smbache\"\namount <- 6.656\naccount <- 1337\nstr_interp(\"User ${user_name} (account $[08d]{account}) has $$[.2f]{amount}.\")\n\n# Nested brace pairs work inside expressions too, and any braces can be\n# placed outside the expressions.\nstr_interp(\"Works with } nested { braces too: $[.2f]{{{2 + 2}*{amount}}}\")\n\n# Values can also come from a list\nstr_interp(\n  \"One value, ${value1}, and then another, ${value2*2}.\",\n  list(value1 = 10, value2 = 20)\n)\n\n# Or a data frame\nstr_interp(\n  \"Values are $[.2f]{max(Sepal.Width)} and $[.2f]{min(Sepal.Width)}.\",\n  iris\n)\n\n# Use a vector when the string is long:\nmax_char <- 80\nstr_interp(c(\n  \"This particular line is so long that it is hard to write \",\n  \"without breaking the ${max_char}-char barrier!\"\n))\n}\n\\seealso{\n\\code{\\link[=str_glue]{str_glue()}} and \\code{\\link[=str_glue_data]{str_glue_data()}} for alternative approaches to\nthe same problem.\n}\n\\author{\nStefan Milton Bache\n}\n\\keyword{internal}\n"
  },
  {
    "path": "man/str_length.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/length.R\n\\name{str_length}\n\\alias{str_length}\n\\alias{str_width}\n\\title{Compute the length/width}\n\\usage{\nstr_length(string)\n\nstr_width(string)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n}\n\\value{\nA numeric vector the same length as \\code{string}.\n}\n\\description{\n\\code{str_length()} returns the number of codepoints in a string. These are\nthe individual elements (which are often, but not always letters) that\ncan be extracted with \\code{\\link[=str_sub]{str_sub()}}.\n\n\\code{str_width()} returns how much space the string will occupy when printed\nin a fixed width font (i.e. when printed in the console).\n}\n\\examples{\nstr_length(letters)\nstr_length(NA)\nstr_length(factor(\"abc\"))\nstr_length(c(\"i\", \"like\", \"programming\", NA))\n\n# Some characters, like emoji and Chinese characters (hanzi), are square\n# which means they take up the width of two Latin characters\nx <- c(\"\\u6c49\\u5b57\", \"\\U0001f60a\")\nstr_view(x)\nstr_width(x)\nstr_length(x)\n\n# There are two ways of representing a u with an umlaut\nu <- c(\"\\u00fc\", \"u\\u0308\")\n# They have the same width\nstr_width(u)\n# But a different length\nstr_length(u)\n# Because the second element is made up of a u + an accent\nstr_sub(u, 1, 1)\n}\n\\seealso{\n\\code{\\link[stringi:stri_length]{stringi::stri_length()}} which this function wraps.\n}\n"
  },
  {
    "path": "man/str_like.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/detect.R\n\\name{str_like}\n\\alias{str_like}\n\\alias{str_ilike}\n\\title{Detect a pattern in the same way as \\code{SQL}'s \\code{LIKE} and \\code{ILIKE} operators}\n\\usage{\nstr_like(string, pattern, ignore_case = deprecated())\n\nstr_ilike(string, pattern)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{A character vector containing a SQL \"like\" pattern.\nSee above for details.}\n\n\\item{ignore_case}{\\ifelse{html}{\\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\\strong{[Deprecated]}}}\n}\n\\value{\nA logical vector the same length as \\code{string}.\n}\n\\description{\n\\code{str_like()} and \\code{str_like()} follow the conventions of the SQL \\code{LIKE}\nand \\code{ILIKE} operators, namely:\n\\itemize{\n\\item Must match the entire string.\n\\item \\verb{_} matches a single character (like \\code{.}).\n\\item \\verb{\\%} matches any number of characters (like \\verb{.*}).\n\\item \\verb{\\\\\\%} and \\verb{\\\\_} match literal \\verb{\\%} and \\verb{_}.\n}\n\nThe difference between the two functions is their case-sensitivity:\n\\code{str_like()} is case sensitive and \\code{str_ilike()} is not.\n}\n\\note{\nPrior to stringr 1.6.0, \\code{str_like()} was incorrectly case-insensitive.\n}\n\\examples{\nfruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\nstr_like(fruit, \"app\")\nstr_like(fruit, \"app\\%\")\nstr_like(fruit, \"APP\\%\")\nstr_like(fruit, \"ba_ana\")\nstr_like(fruit, \"\\%apple\")\n\nstr_ilike(fruit, \"app\")\nstr_ilike(fruit, \"app\\%\")\nstr_ilike(fruit, \"APP\\%\")\nstr_ilike(fruit, \"ba_ana\")\nstr_ilike(fruit, \"\\%apple\")\n}\n"
  },
  {
    "path": "man/str_locate.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/locate.R\n\\name{str_locate}\n\\alias{str_locate}\n\\alias{str_locate_all}\n\\title{Find location of match}\n\\usage{\nstr_locate(string, pattern)\n\nstr_locate_all(string, pattern)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nMatch character, word, line and sentence boundaries with\n\\code{\\link[=boundary]{boundary()}}. The empty string, \\verb{\"\"``, is equivalent to }boundary(\"character\")`.}\n}\n\\value{\n\\itemize{\n\\item \\code{str_locate()} returns an integer matrix with two columns and\none row for each element of \\code{string}. The first column, \\code{start},\ngives the position at the start of the match, and the second column, \\code{end},\ngives the position of the end.\n\\item \\code{str_locate_all()} returns a list of integer matrices with the same\nlength as \\code{string}/\\code{pattern}. The matrices have columns \\code{start} and \\code{end}\nas above, and one row for each match.\n}\n}\n\\description{\n\\code{str_locate()} returns the \\code{start} and \\code{end} position of the first match;\n\\code{str_locate_all()} returns the \\code{start} and \\code{end} position of each match.\n\nBecause the \\code{start} and \\code{end} values are inclusive, zero-length matches\n(e.g. \\code{$}, \\code{^}, \\verb{\\\\\\\\b}) will have an \\code{end} that is smaller than \\code{start}.\n}\n\\examples{\nfruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\nstr_locate(fruit, \"$\")\nstr_locate(fruit, \"a\")\nstr_locate(fruit, \"e\")\nstr_locate(fruit, c(\"a\", \"b\", \"p\", \"p\"))\n\nstr_locate_all(fruit, \"a\")\nstr_locate_all(fruit, \"e\")\nstr_locate_all(fruit, c(\"a\", \"b\", \"p\", \"p\"))\n\n# Find location of every character\nstr_locate_all(fruit, \"\")\n}\n\\seealso{\n\\code{\\link[=str_extract]{str_extract()}} for a convenient way of extracting matches,\n\\code{\\link[stringi:stri_locate]{stringi::stri_locate()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_match.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/match.R\n\\name{str_match}\n\\alias{str_match}\n\\alias{str_match_all}\n\\title{Extract components (capturing groups) from a match}\n\\usage{\nstr_match(string, pattern)\n\nstr_match_all(string, pattern)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Unlike other stringr functions, \\code{str_match()} only supports\nregular expressions, as described \\code{vignette(\"regular-expressions\")}.\nThe pattern should contain at least one capturing group.}\n}\n\\value{\n\\itemize{\n\\item \\code{str_match()}: a character matrix with the same number of rows as the\nlength of \\code{string}/\\code{pattern}. The first column is the complete match,\nfollowed by one column for each capture group. The columns will be named\nif you used \"named captured groups\", i.e. \\verb{(?<name>pattern')}.\n\\item \\code{str_match_all()}: a list of the same length as \\code{string}/\\code{pattern}\ncontaining character matrices. Each matrix has columns as described above\nand one row for each match.\n}\n}\n\\description{\nExtract any number of matches defined by unnamed, \\code{(pattern)}, and\nnamed, \\verb{(?<name>pattern)} capture groups.\n\nUse a non-capturing group, \\verb{(?:pattern)}, if you need to override default\noperate precedence but don't want to capture the result.\n}\n\\examples{\nstrings <- c(\" 219 733 8965\", \"329-293-8753 \", \"banana\", \"595 794 7569\",\n  \"387 287 6718\", \"apple\", \"233.398.9187  \", \"482 952 3315\",\n  \"239 923 8115 and 842 566 4692\", \"Work: 579-499-7527\", \"$1000\",\n  \"Home: 543.355.3679\")\nphone <- \"([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})\"\n\nstr_extract(strings, phone)\nstr_match(strings, phone)\n\n# Extract/match all\nstr_extract_all(strings, phone)\nstr_match_all(strings, phone)\n\n# You can also name the groups to make further manipulation easier\nphone <- \"(?<area>[2-9][0-9]{2})[- .](?<phone>[0-9]{3}[- .][0-9]{4})\"\nstr_match(strings, phone)\n\nx <- c(\"<a> <b>\", \"<a> <>\", \"<a>\", \"\", NA)\nstr_match(x, \"<(.*?)> <(.*?)>\")\nstr_match_all(x, \"<(.*?)>\")\n\nstr_extract(x, \"<.*?>\")\nstr_extract_all(x, \"<.*?>\")\n}\n\\seealso{\n\\code{\\link[=str_extract]{str_extract()}} to extract the complete match,\n\\code{\\link[stringi:stri_match]{stringi::stri_match()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_order.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/sort.R\n\\name{str_order}\n\\alias{str_order}\n\\alias{str_rank}\n\\alias{str_sort}\n\\title{Order, rank, or sort a character vector}\n\\usage{\nstr_order(\n  x,\n  decreasing = FALSE,\n  na_last = TRUE,\n  locale = \"en\",\n  numeric = FALSE,\n  ...\n)\n\nstr_rank(x, locale = \"en\", numeric = FALSE, ...)\n\nstr_sort(\n  x,\n  decreasing = FALSE,\n  na_last = TRUE,\n  locale = \"en\",\n  numeric = FALSE,\n  ...\n)\n}\n\\arguments{\n\\item{x}{A character vector to sort.}\n\n\\item{decreasing}{A boolean. If \\code{FALSE}, the default, sorts from\nlowest to highest; if \\code{TRUE} sorts from highest to lowest.}\n\n\\item{na_last}{Where should \\code{NA} go? \\code{TRUE} at the end,\n\\code{FALSE} at the beginning, \\code{NA} dropped.}\n\n\\item{locale}{Locale to use for comparisons. See\n\\code{\\link[stringi:stri_locale_list]{stringi::stri_locale_list()}} for all possible options.\nDefaults to \"en\" (English) to ensure that default behaviour is\nconsistent across platforms.}\n\n\\item{numeric}{If \\code{TRUE}, will sort digits numerically, instead\nof as strings.}\n\n\\item{...}{Other options used to control collation. Passed on to\n\\code{\\link[stringi:stri_opts_collator]{stringi::stri_opts_collator()}}.}\n}\n\\value{\nA character vector the same length as \\code{string}.\n}\n\\description{\n\\itemize{\n\\item \\code{str_sort()} returns the sorted vector.\n\\item \\code{str_order()} returns an integer vector that returns the desired\norder when used for subsetting, i.e. \\code{x[str_order(x)]} is the same\nas \\code{str_sort()}\n\\item \\code{str_rank()} returns the ranks of the values, i.e.\n\\code{arrange(df, str_rank(x))} is the same as \\code{str_sort(df$x)}.\n}\n}\n\\examples{\nx <- c(\"apple\", \"car\", \"happy\", \"char\")\nstr_sort(x)\n\nstr_order(x)\nx[str_order(x)]\n\nstr_rank(x)\n\n# In Czech, ch is a digraph that sorts after h\nstr_sort(x, locale = \"cs\")\n\n# Use numeric = TRUE to sort numbers in strings\nx <- c(\"100a10\", \"100a5\", \"2b\", \"2a\")\nstr_sort(x)\nstr_sort(x, numeric = TRUE)\n}\n\\seealso{\n\\code{\\link[stringi:stri_order]{stringi::stri_order()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_pad.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/pad.R\n\\name{str_pad}\n\\alias{str_pad}\n\\title{Pad a string to minimum width}\n\\usage{\nstr_pad(\n  string,\n  width,\n  side = c(\"left\", \"right\", \"both\"),\n  pad = \" \",\n  use_width = TRUE\n)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{width}{Minimum width of padded strings.}\n\n\\item{side}{Side on which padding character is added (left, right or both).}\n\n\\item{pad}{Single padding character (default is a space).}\n\n\\item{use_width}{If \\code{FALSE}, use the length of the string instead of the\nwidth; see \\code{\\link[=str_width]{str_width()}}/\\code{\\link[=str_length]{str_length()}} for the difference.}\n}\n\\value{\nA character vector the same length as \\code{stringr}/\\code{width}/\\code{pad}.\n}\n\\description{\nPad a string to a fixed width, so that\n\\code{str_length(str_pad(x, n))} is always greater than or equal to \\code{n}.\n}\n\\examples{\nrbind(\n  str_pad(\"hadley\", 30, \"left\"),\n  str_pad(\"hadley\", 30, \"right\"),\n  str_pad(\"hadley\", 30, \"both\")\n)\n\n# All arguments are vectorised except side\nstr_pad(c(\"a\", \"abc\", \"abcdef\"), 10)\nstr_pad(\"a\", c(5, 10, 20))\nstr_pad(\"a\", 10, pad = c(\"-\", \"_\", \" \"))\n\n# Longer strings are returned unchanged\nstr_pad(\"hadley\", 3)\n}\n\\seealso{\n\\code{\\link[=str_trim]{str_trim()}} to remove whitespace;\n\\code{\\link[=str_trunc]{str_trunc()}} to decrease the maximum width of a string.\n}\n"
  },
  {
    "path": "man/str_remove.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/remove.R\n\\name{str_remove}\n\\alias{str_remove}\n\\alias{str_remove_all}\n\\title{Remove matched patterns}\n\\usage{\nstr_remove(string, pattern)\n\nstr_remove_all(string, pattern)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nYou can not match boundaries, including \\code{\"\"}, with this function.}\n}\n\\value{\nA character vector the same length as \\code{string}/\\code{pattern}.\n}\n\\description{\nRemove matches, i.e. replace them with \\code{\"\"}.\n}\n\\examples{\nfruits <- c(\"one apple\", \"two pears\", \"three bananas\")\nstr_remove(fruits, \"[aeiou]\")\nstr_remove_all(fruits, \"[aeiou]\")\n}\n\\seealso{\n\\code{\\link[=str_replace]{str_replace()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_replace.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/replace.R\n\\name{str_replace}\n\\alias{str_replace}\n\\alias{str_replace_all}\n\\title{Replace matches with new text}\n\\usage{\nstr_replace(string, pattern, replacement)\n\nstr_replace_all(string, pattern, replacement)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described\nin \\link[stringi:about_search_regex]{stringi::about_search_regex}. Control options with\n\\code{\\link[=regex]{regex()}}.\n\nFor \\code{str_replace_all()} this can also be a named vector\n(\\code{c(pattern1 = replacement1)}), in order to perform multiple replacements\nin each element of \\code{string}.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nYou can not match boundaries, including \\code{\"\"}, with this function.}\n\n\\item{replacement}{The replacement value, usually a single string,\nbut it can be the a vector the same length as \\code{string} or \\code{pattern}.\nReferences of the form \\verb{\\\\1}, \\verb{\\\\2}, etc will be replaced with\nthe contents of the respective matched group (created by \\verb{()}).\n\nAlternatively, supply a function (or formula): it will be passed a single\ncharacter vector and should return a character vector of the same length.\n\nTo replace the complete string with \\code{NA}, use\n\\code{replacement = NA_character_}.}\n}\n\\value{\nA character vector the same length as\n\\code{string}/\\code{pattern}/\\code{replacement}.\n}\n\\description{\n\\code{str_replace()} replaces the first match; \\code{str_replace_all()} replaces\nall matches.\n}\n\\examples{\nfruits <- c(\"one apple\", \"two pears\", \"three bananas\")\nstr_replace(fruits, \"[aeiou]\", \"-\")\nstr_replace_all(fruits, \"[aeiou]\", \"-\")\nstr_replace_all(fruits, \"[aeiou]\", toupper)\nstr_replace_all(fruits, \"b\", NA_character_)\n\nstr_replace(fruits, \"([aeiou])\", \"\")\nstr_replace(fruits, \"([aeiou])\", \"\\\\\\\\1\\\\\\\\1\")\n\n# Note that str_replace() is vectorised along text, pattern, and replacement\nstr_replace(fruits, \"[aeiou]\", c(\"1\", \"2\", \"3\"))\nstr_replace(fruits, c(\"a\", \"e\", \"i\"), \"-\")\n\n# If you want to apply multiple patterns and replacements to the same\n# string, pass a named vector to pattern.\nfruits \\%>\\%\n  str_c(collapse = \"---\") \\%>\\%\n  str_replace_all(c(\"one\" = \"1\", \"two\" = \"2\", \"three\" = \"3\"))\n\n# Use a function for more sophisticated replacement. This example\n# replaces colour names with their hex values.\ncolours <- str_c(\"\\\\\\\\b\", colors(), \"\\\\\\\\b\", collapse=\"|\")\ncol2hex <- function(col) {\n  rgb <- col2rgb(col)\n  rgb(rgb[\"red\", ], rgb[\"green\", ], rgb[\"blue\", ], maxColorValue = 255)\n}\n\nx <- c(\n  \"Roses are red, violets are blue\",\n  \"My favourite colour is green\"\n)\nstr_replace_all(x, colours, col2hex)\n}\n\\seealso{\n\\code{\\link[=str_replace_na]{str_replace_na()}} to turn missing values into \"NA\";\n\\code{\\link[stringi:stri_replace]{stringi::stri_replace()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_replace_na.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/replace.R\n\\name{str_replace_na}\n\\alias{str_replace_na}\n\\title{Turn NA into \"NA\"}\n\\usage{\nstr_replace_na(string, replacement = \"NA\")\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{replacement}{A single string.}\n}\n\\description{\nTurn NA into \"NA\"\n}\n\\examples{\nstr_replace_na(c(NA, \"abc\", \"def\"))\n}\n"
  },
  {
    "path": "man/str_split.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/split.R\n\\name{str_split}\n\\alias{str_split}\n\\alias{str_split_1}\n\\alias{str_split_fixed}\n\\alias{str_split_i}\n\\title{Split up a string into pieces}\n\\usage{\nstr_split(string, pattern, n = Inf, simplify = FALSE)\n\nstr_split_1(string, pattern)\n\nstr_split_fixed(string, pattern, n)\n\nstr_split_i(string, pattern, i)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nMatch character, word, line and sentence boundaries with\n\\code{\\link[=boundary]{boundary()}}. The empty string, \\verb{\"\"``, is equivalent to }boundary(\"character\")`.}\n\n\\item{n}{Maximum number of pieces to return. Default (Inf) uses all\npossible split positions.\n\nFor \\code{str_split()}, this determines the maximum length of each element\nof the output. For \\code{str_split_fixed()}, this determines the number of\ncolumns in the output; if an input is too short, the result will be padded\nwith \\code{\"\"}.}\n\n\\item{simplify}{A boolean.\n\\itemize{\n\\item \\code{FALSE} (the default): returns a list of character vectors.\n\\item \\code{TRUE}: returns a character matrix.\n}}\n\n\\item{i}{Element to return. Use a negative value to count from the\nright hand side.}\n}\n\\value{\n\\itemize{\n\\item \\code{str_split_1()}: a character vector.\n\\item \\code{str_split()}: a list the same length as \\code{string}/\\code{pattern} containing\ncharacter vectors.\n\\item \\code{str_split_fixed()}: a character matrix with \\code{n} columns and the same\nnumber of rows as the length of \\code{string}/\\code{pattern}.\n\\item \\code{str_split_i()}: a character vector the same length as \\code{string}/\\code{pattern}.\n}\n}\n\\description{\nThis family of functions provides various ways of splitting a string up\ninto pieces. These two functions return a character vector:\n\\itemize{\n\\item \\code{str_split_1()} takes a single string and splits it into pieces,\nreturning a single character vector.\n\\item \\code{str_split_i()} splits each string in a character vector into pieces and\nextracts the \\code{i}th value, returning a character vector.\n}\n\nThese two functions return a more complex object:\n\\itemize{\n\\item \\code{str_split()} splits each string in a character vector into a varying\nnumber of pieces, returning a list of character vectors.\n\\item \\code{str_split_fixed()} splits each string in a character vector into a\nfixed number of pieces, returning a character matrix.\n}\n}\n\\examples{\nfruits <- c(\n  \"apples and oranges and pears and bananas\",\n  \"pineapples and mangos and guavas\"\n)\n\nstr_split(fruits, \" and \")\nstr_split(fruits, \" and \", simplify = TRUE)\n\n# If you want to split a single string, use `str_split_1`\nstr_split_1(fruits[[1]], \" and \")\n\n# Specify n to restrict the number of possible matches\nstr_split(fruits, \" and \", n = 3)\nstr_split(fruits, \" and \", n = 2)\n# If n greater than number of pieces, no padding occurs\nstr_split(fruits, \" and \", n = 5)\n\n# Use fixed to return a character matrix\nstr_split_fixed(fruits, \" and \", 3)\nstr_split_fixed(fruits, \" and \", 4)\n\n# str_split_i extracts only a single piece from a string\nstr_split_i(fruits, \" and \", 1)\nstr_split_i(fruits, \" and \", 4)\n# use a negative number to select from the end\nstr_split_i(fruits, \" and \", -1)\n}\n\\seealso{\n\\code{\\link[stringi:stri_split]{stringi::stri_split()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_starts.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/detect.R\n\\name{str_starts}\n\\alias{str_starts}\n\\alias{str_ends}\n\\title{Detect the presence/absence of a match at the start/end}\n\\usage{\nstr_starts(string, pattern, negate = FALSE)\n\nstr_ends(string, pattern, negate = FALSE)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern with which the string starts or ends.\n\nThe default interpretation is a regular expression, as described in\n\\link[stringi:about_search_regex]{stringi::about_search_regex}. Control options with \\code{\\link[=regex]{regex()}}.\n\nMatch a fixed string (i.e. by comparing only bytes), using \\code{\\link[=fixed]{fixed()}}. This\nis fast, but approximate. Generally, for matching human text, you'll want\n\\code{\\link[=coll]{coll()}} which respects character matching rules for the specified locale.}\n\n\\item{negate}{If \\code{TRUE}, inverts the resulting boolean vector.}\n}\n\\value{\nA logical vector.\n}\n\\description{\n\\code{str_starts()} and \\code{str_ends()} are special cases of \\code{\\link[=str_detect]{str_detect()}} that\nonly match at the beginning or end of a string, respectively.\n}\n\\examples{\nfruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\nstr_starts(fruit, \"p\")\nstr_starts(fruit, \"p\", negate = TRUE)\nstr_ends(fruit, \"e\")\nstr_ends(fruit, \"e\", negate = TRUE)\n}\n"
  },
  {
    "path": "man/str_sub.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/sub.R\n\\name{str_sub}\n\\alias{str_sub}\n\\alias{str_sub<-}\n\\alias{str_sub_all}\n\\title{Get and set substrings using their positions}\n\\usage{\nstr_sub(string, start = 1L, end = -1L)\n\nstr_sub(string, start = 1L, end = -1L, omit_na = FALSE) <- value\n\nstr_sub_all(string, start = 1L, end = -1L)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{start, end}{A pair of integer vectors defining the range of characters\nto extract (inclusive). Positive values count from the left of the string,\nand negative values count from the right. In other words, if \\code{string} is\n\\code{\"abcdef\"} then 1 refers to \\code{\"a\"} and -1 refers to \\code{\"f\"}.\n\nAlternatively, instead of a pair of vectors, you can pass a matrix to\n\\code{start}. The matrix should have two columns, either labelled \\code{start}\nand \\code{end}, or \\code{start} and \\code{length}. This makes \\code{str_sub()} work directly\nwith the output from \\code{\\link[=str_locate]{str_locate()}} and friends.}\n\n\\item{omit_na}{Single logical value. If \\code{TRUE}, missing values in any of the\narguments provided will result in an unchanged input.}\n\n\\item{value}{Replacement string.}\n}\n\\value{\n\\itemize{\n\\item \\code{str_sub()}: A character vector the same length as \\code{string}/\\code{start}/\\code{end}.\n\\item \\code{str_sub_all()}: A list the same length as \\code{string}. Each element is\na character vector the same length as \\code{start}/\\code{end}.\n}\n\nIf \\code{end} comes before \\code{start} or \\code{start} is outside the range of \\code{string}\nthen the corresponding output will be the empty string.\n}\n\\description{\n\\code{str_sub()} extracts or replaces the elements at a single position in each\nstring. \\code{str_sub_all()} allows you to extract strings at multiple elements\nin every string.\n}\n\\examples{\nhw <- \"Hadley Wickham\"\n\nstr_sub(hw, 1, 6)\nstr_sub(hw, end = 6)\nstr_sub(hw, 8, 14)\nstr_sub(hw, 8)\n\n# Negative values index from end of string\nstr_sub(hw, -1)\nstr_sub(hw, -7)\nstr_sub(hw, end = -7)\n\n# str_sub() is vectorised by both string and position\nstr_sub(hw, c(1, 8), c(6, 14))\n\n# if you want to extract multiple positions from multiple strings,\n# use str_sub_all()\nx <- c(\"abcde\", \"ghifgh\")\nstr_sub(x, c(1, 2), c(2, 4))\nstr_sub_all(x, start = c(1, 2), end = c(2, 4))\n\n# Alternatively, you can pass in a two column matrix, as in the\n# output from str_locate_all\npos <- str_locate_all(hw, \"[aeio]\")[[1]]\npos\nstr_sub(hw, pos)\n\n# You can also use `str_sub()` to modify strings:\nx <- \"BBCDEF\"\nstr_sub(x, 1, 1) <- \"A\"; x\nstr_sub(x, -1, -1) <- \"K\"; x\nstr_sub(x, -2, -2) <- \"GHIJ\"; x\nstr_sub(x, 2, -2) <- \"\"; x\n}\n\\seealso{\nThe underlying implementation in \\code{\\link[stringi:stri_sub]{stringi::stri_sub()}}\n}\n"
  },
  {
    "path": "man/str_subset.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/subset.R\n\\name{str_subset}\n\\alias{str_subset}\n\\title{Find matching elements}\n\\usage{\nstr_subset(string, pattern, negate = FALSE)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nYou can not match boundaries, including \\code{\"\"}, with this function.}\n\n\\item{negate}{If \\code{TRUE}, inverts the resulting boolean vector.}\n}\n\\value{\nA character vector, usually smaller than \\code{string}.\n}\n\\description{\n\\code{str_subset()} returns all elements of \\code{string} where there's at least\none match to \\code{pattern}. It's a wrapper around \\code{x[str_detect(x, pattern)]},\nand is equivalent to \\code{grep(pattern, x, value = TRUE)}.\n\nUse \\code{\\link[=str_extract]{str_extract()}} to find the location of the match \\emph{within} each string.\n}\n\\examples{\nfruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\nstr_subset(fruit, \"a\")\n\nstr_subset(fruit, \"^a\")\nstr_subset(fruit, \"a$\")\nstr_subset(fruit, \"b\")\nstr_subset(fruit, \"[aeiou]\")\n\n# Elements that don't match\nstr_subset(fruit, \"^p\", negate = TRUE)\n\n# Missings never match\nstr_subset(c(\"a\", NA, \"b\"), \".\")\n}\n\\seealso{\n\\code{\\link[=grep]{grep()}} with argument \\code{value = TRUE},\n\\code{\\link[stringi:stri_subset]{stringi::stri_subset()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/str_to_camel.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/case.R\n\\name{str_to_camel}\n\\alias{str_to_camel}\n\\alias{str_to_snake}\n\\alias{str_to_kebab}\n\\title{Convert between different types of programming case}\n\\usage{\nstr_to_camel(string, first_upper = FALSE)\n\nstr_to_snake(string)\n\nstr_to_kebab(string)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{first_upper}{Logical. Should the first letter be capitalized?}\n}\n\\description{\n\\itemize{\n\\item \\code{str_to_camel()} converts to camel case, where the first letter of\neach word is capitalized, with no separation between words. By default\nthe first letter of the first word is not capitalized.\n\\item \\code{str_to_kebab()} converts to kebab case, where words are converted to\nlower case and separated by dashes (\\code{-}).\n\\item \\code{str_to_snake()} converts to snake case, where words are converted to\nlower case and separated by underscores (\\verb{_}).\n}\n}\n\\examples{\nstr_to_camel(\"my-variable\")\nstr_to_camel(\"my-variable\", first_upper = TRUE)\n\nstr_to_snake(\"MyVariable\")\nstr_to_kebab(\"MyVariable\")\n}\n"
  },
  {
    "path": "man/str_trim.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/trim.R\n\\name{str_trim}\n\\alias{str_trim}\n\\alias{str_squish}\n\\title{Remove whitespace}\n\\usage{\nstr_trim(string, side = c(\"both\", \"left\", \"right\"))\n\nstr_squish(string)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{side}{Side on which to remove whitespace: \"left\", \"right\", or\n\"both\", the default.}\n}\n\\value{\nA character vector the same length as \\code{string}.\n}\n\\description{\n\\code{str_trim()} removes whitespace from start and end of string; \\code{str_squish()}\nremoves whitespace at the start and end, and replaces all internal whitespace\nwith a single space.\n}\n\\examples{\nstr_trim(\"  String with trailing and leading white space\\t\")\nstr_trim(\"\\n\\nString with trailing and leading white space\\n\\n\")\n\nstr_squish(\"  String with trailing,  middle, and leading white space\\t\")\nstr_squish(\"\\n\\nString with excess,  trailing and leading white   space\\n\\n\")\n}\n\\seealso{\n\\code{\\link[=str_pad]{str_pad()}} to add whitespace\n}\n"
  },
  {
    "path": "man/str_trunc.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/trunc.R\n\\name{str_trunc}\n\\alias{str_trunc}\n\\title{Truncate a string to maximum width}\n\\usage{\nstr_trunc(string, width, side = c(\"right\", \"left\", \"center\"), ellipsis = \"...\")\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{width}{Maximum width of string.}\n\n\\item{side, ellipsis}{Location and content of ellipsis that indicates\ncontent has been removed.}\n}\n\\value{\nA character vector the same length as \\code{string}.\n}\n\\description{\nTruncate a string to a fixed of characters, so that\n\\code{str_length(str_trunc(x, n))} is always less than or equal to \\code{n}.\n}\n\\examples{\nx <- \"This string is moderately long\"\nrbind(\n  str_trunc(x, 20, \"right\"),\n  str_trunc(x, 20, \"left\"),\n  str_trunc(x, 20, \"center\")\n)\n}\n\\seealso{\n\\code{\\link[=str_pad]{str_pad()}} to increase the minimum width of a string.\n}\n"
  },
  {
    "path": "man/str_unique.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/unique.R\n\\name{str_unique}\n\\alias{str_unique}\n\\title{Remove duplicated strings}\n\\usage{\nstr_unique(string, locale = \"en\", ignore_case = FALSE, ...)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{locale}{Locale to use for comparisons. See\n\\code{\\link[stringi:stri_locale_list]{stringi::stri_locale_list()}} for all possible options.\nDefaults to \"en\" (English) to ensure that default behaviour is\nconsistent across platforms.}\n\n\\item{ignore_case}{Ignore case when comparing strings?}\n\n\\item{...}{Other options used to control collation. Passed on to\n\\code{\\link[stringi:stri_opts_collator]{stringi::stri_opts_collator()}}.}\n}\n\\value{\nA character vector, usually shorter than \\code{string}.\n}\n\\description{\n\\code{str_unique()} removes duplicated values, with optional control over\nhow duplication is measured.\n}\n\\examples{\nstr_unique(c(\"a\", \"b\", \"c\", \"b\", \"a\"))\n\nstr_unique(c(\"a\", \"b\", \"c\", \"B\", \"A\"))\nstr_unique(c(\"a\", \"b\", \"c\", \"B\", \"A\"), ignore_case = TRUE)\n\n# Use ... to pass additional arguments to stri_unique()\nstr_unique(c(\"motley\", \"mötley\", \"pinguino\", \"pingüino\"))\nstr_unique(c(\"motley\", \"mötley\", \"pinguino\", \"pingüino\"), strength = 1)\n}\n\\seealso{\n\\code{\\link[=unique]{unique()}}, \\code{\\link[stringi:stri_unique]{stringi::stri_unique()}} which this function wraps.\n}\n"
  },
  {
    "path": "man/str_view.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/view.R\n\\name{str_view}\n\\alias{str_view}\n\\alias{str_view_all}\n\\title{View strings and matches}\n\\usage{\nstr_view(\n  string,\n  pattern = NULL,\n  match = TRUE,\n  html = FALSE,\n  use_escapes = FALSE\n)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nYou can not match boundaries, including \\code{\"\"}, with this function.}\n\n\\item{match}{If \\code{pattern} is supplied, which elements should be shown?\n\\itemize{\n\\item \\code{TRUE}, the default, shows only elements that match the pattern.\n\\item \\code{NA} shows all elements.\n\\item \\code{FALSE} shows only elements that don't match the pattern.\n}\n\nIf \\code{pattern} is not supplied, all elements are always shown.}\n\n\\item{html}{Use HTML output? If \\code{TRUE} will create an HTML widget; if \\code{FALSE}\nwill style using ANSI escapes.}\n\n\\item{use_escapes}{If \\code{TRUE}, all non-ASCII characters will be rendered\nwith unicode escapes. This is useful to see exactly what underlying\nvalues are stored in the string.}\n}\n\\description{\n\\code{str_view()} is used to print the underlying representation of a string and\nto see how a \\code{pattern} matches.\n\nMatches are surrounded by \\verb{<>} and unusual whitespace (i.e. all whitespace\napart from \\code{\" \"} and \\code{\"\\\\n\"}) are surrounded by \\code{{}} and escaped. Where\npossible, matches and unusual whitespace are coloured blue and \\code{NA}s red.\n}\n\\examples{\n# Show special characters\nstr_view(c(\"\\\"\\\\\\\\\", \"\\\\\\\\\\\\\\\\\\\\\\\\\", \"fgh\", NA, \"NA\"))\n\n# A non-breaking space looks like a regular space:\nnbsp <- \"Hi\\u00A0you\"\nnbsp\n# But it doesn't behave like one:\nstr_detect(nbsp, \" \")\n# So str_view() brings it to your attention with a blue background\nstr_view(nbsp)\n\n# You can also use escapes to see all non-ASCII characters\nstr_view(nbsp, use_escapes = TRUE)\n\n# Supply a pattern to see where it matches\nstr_view(c(\"abc\", \"def\", \"fghi\"), \"[aeiou]\")\nstr_view(c(\"abc\", \"def\", \"fghi\"), \"^\")\nstr_view(c(\"abc\", \"def\", \"fghi\"), \"..\")\n\n# By default, only matching strings will be shown\nstr_view(c(\"abc\", \"def\", \"fghi\"), \"e\")\n# but you can show all:\nstr_view(c(\"abc\", \"def\", \"fghi\"), \"e\", match = NA)\n# or just those that don't match:\nstr_view(c(\"abc\", \"def\", \"fghi\"), \"e\", match = FALSE)\n}\n"
  },
  {
    "path": "man/str_which.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/subset.R\n\\name{str_which}\n\\alias{str_which}\n\\title{Find matching indices}\n\\usage{\nstr_which(string, pattern, negate = FALSE)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{pattern}{Pattern to look for.\n\nThe default interpretation is a regular expression, as described in\n\\code{vignette(\"regular-expressions\")}. Use \\code{\\link[=regex]{regex()}} for finer control of the\nmatching behaviour.\n\nMatch a fixed string (i.e. by comparing only bytes), using\n\\code{\\link[=fixed]{fixed()}}. This is fast, but approximate. Generally,\nfor matching human text, you'll want \\code{\\link[=coll]{coll()}} which\nrespects character matching rules for the specified locale.\n\nYou can not match boundaries, including \\code{\"\"}, with this function.}\n\n\\item{negate}{If \\code{TRUE}, inverts the resulting boolean vector.}\n}\n\\value{\nAn integer vector, usually smaller than \\code{string}.\n}\n\\description{\n\\code{str_which()} returns the indices of \\code{string} where there's at least\none match to \\code{pattern}. It's a wrapper around\n\\code{which(str_detect(x, pattern))}, and is equivalent to \\code{grep(pattern, x)}.\n}\n\\examples{\nfruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\nstr_which(fruit, \"a\")\n\n# Elements that don't match\nstr_which(fruit, \"^p\", negate = TRUE)\n\n# Missings never match\nstr_which(c(\"a\", NA, \"b\"), \".\")\n}\n"
  },
  {
    "path": "man/str_wrap.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/wrap.R\n\\name{str_wrap}\n\\alias{str_wrap}\n\\title{Wrap words into nicely formatted paragraphs}\n\\usage{\nstr_wrap(string, width = 80, indent = 0, exdent = 0, whitespace_only = TRUE)\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{width}{Positive integer giving target line width (in number of\ncharacters). A width less than or equal to 1 will put each word on its\nown line.}\n\n\\item{indent, exdent}{A non-negative integer giving the indent for the\nfirst line (\\code{indent}) and all subsequent lines (\\code{exdent}).}\n\n\\item{whitespace_only}{A boolean.\n\\itemize{\n\\item If \\code{TRUE} (the default) wrapping will only occur at whitespace.\n\\item If \\code{FALSE}, can break on any non-word character (e.g. \\code{/}, \\code{-}).\n}}\n}\n\\value{\nA character vector the same length as \\code{string}.\n}\n\\description{\nWrap words into paragraphs, minimizing the \"raggedness\" of the lines\n(i.e. the variation in length line) using the Knuth-Plass algorithm.\n}\n\\examples{\nthanks_path <- file.path(R.home(\"doc\"), \"THANKS\")\nthanks <- str_c(readLines(thanks_path), collapse = \"\\n\")\nthanks <- word(thanks, 1, 3, fixed(\"\\n\\n\"))\ncat(str_wrap(thanks), \"\\n\")\ncat(str_wrap(thanks, width = 40), \"\\n\")\ncat(str_wrap(thanks, width = 60, indent = 2), \"\\n\")\ncat(str_wrap(thanks, width = 60, exdent = 2), \"\\n\")\ncat(str_wrap(thanks, width = 0, exdent = 2), \"\\n\")\n}\n\\seealso{\n\\code{\\link[stringi:stri_wrap]{stringi::stri_wrap()}} for the underlying implementation.\n}\n"
  },
  {
    "path": "man/stringr-data.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/data.R\n\\docType{data}\n\\name{stringr-data}\n\\alias{stringr-data}\n\\alias{sentences}\n\\alias{fruit}\n\\alias{words}\n\\title{Sample character vectors for practicing string manipulations}\n\\format{\nCharacter vectors.\n}\n\\usage{\nsentences\n\nfruit\n\nwords\n}\n\\description{\n\\code{fruit} and \\code{words} come from the \\code{rcorpora} package\nwritten by Gabor Csardi; the data was collected by Darius Kazemi\nand made available at \\url{https://github.com/dariusk/corpora}.\n\\code{sentences} is a collection of \"Harvard sentences\" used for\nstandardised testing of voice.\n}\n\\examples{\nlength(sentences)\nsentences[1:5]\n\nlength(fruit)\nfruit[1:5]\n\nlength(words)\nwords[1:5]\n}\n\\keyword{datasets}\n"
  },
  {
    "path": "man/stringr-package.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/stringr-package.R\n\\docType{package}\n\\name{stringr-package}\n\\alias{stringr}\n\\alias{stringr-package}\n\\title{stringr: Simple, Consistent Wrappers for Common String Operations}\n\\description{\n\\if{html}{\\figure{logo.png}{options: style='float: right' alt='logo' width='120'}}\n\nA consistent, simple and easy to use set of wrappers around the fantastic 'stringi' package. All function and argument names (and positions) are consistent, all functions deal with \"NA\"'s and zero length vectors in the same way, and the output from one function is easy to feed into the input of another.\n}\n\\seealso{\nUseful links:\n\\itemize{\n  \\item \\url{https://stringr.tidyverse.org}\n  \\item \\url{https://github.com/tidyverse/stringr}\n  \\item Report bugs at \\url{https://github.com/tidyverse/stringr/issues}\n}\n\n}\n\\author{\n\\strong{Maintainer}: Hadley Wickham \\email{hadley@posit.co} [copyright holder]\n\nOther contributors:\n\\itemize{\n  \\item Posit Software, PBC [copyright holder, funder]\n}\n\n}\n\\keyword{internal}\n"
  },
  {
    "path": "man/word.Rd",
    "content": "% Generated by roxygen2: do not edit by hand\n% Please edit documentation in R/word.R\n\\name{word}\n\\alias{word}\n\\title{Extract words from a sentence}\n\\usage{\nword(string, start = 1L, end = start, sep = fixed(\" \"))\n}\n\\arguments{\n\\item{string}{Input vector. Either a character vector, or something\ncoercible to one.}\n\n\\item{start, end}{Pair of integer vectors giving range of words (inclusive)\nto extract. If negative, counts backwards from the last word.\n\nThe default value select the first word.}\n\n\\item{sep}{Separator between words. Defaults to single space.}\n}\n\\value{\nA character vector with the same length as \\code{string}/\\code{start}/\\code{end}.\n}\n\\description{\nExtract words from a sentence\n}\n\\examples{\nsentences <- c(\"Jane saw a cat\", \"Jane sat down\")\nword(sentences, 1)\nword(sentences, 2)\nword(sentences, -1)\nword(sentences, 2, -1)\n\n# Also vectorised over start and end\nword(sentences[1], 1:3, -1)\nword(sentences[1], 1, 1:4)\n\n# Can define words by other separators\nstr <- 'abc.def..123.4568.999'\nword(str, 1, sep = fixed('..'))\nword(str, 2, sep = fixed('..'))\n}\n"
  },
  {
    "path": "po/R-es.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: stringr 1.5.1.9000\\n\"\n\"POT-Creation-Date: 2024-07-17 11:07-0500\\n\"\n\"PO-Revision-Date: 2024-07-17 11:07-0500\\n\"\n\"Last-Translator: Automatically generated\\n\"\n\"Language-Team: none\\n\"\n\"Language: es\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\n#: detect.R:141\nmsgid \"{.arg pattern} must be a plain string, not a stringr modifier.\"\nmsgstr \"{.arg pattern} debe ser una cadena de caracteres, no un modificador de stringr\"\n\n#: interp.R:105\nmsgid \"Invalid template string for interpolation.\"\nmsgstr \"Plantilla de cadenas invalida para interpolación.\"\n\n#: interp.R:176\nmsgid \"Failed to parse input {.str {text}}\"\nmsgstr \"Fallo en segmentar el input {.str {text}}\"\n\n#: match.R:54 match.R:68\nmsgid \"{.arg pattern} must be a regular expression.\"\nmsgstr \"{.arg pattern} debe ser una expresión regular.\"\n\n#: modifiers.R:216\nmsgid \"{.arg pattern} must be a string, not {.obj_type_friendly {x}}.\"\nmsgstr \"{.arg pattern} debe ser una cadena de caracteres, no {.obj_type_friendly {x}}.\"\n\n#: replace.R:208\nmsgid \"Failed to apply {.arg replacement} function.\"\nmsgstr \"Fallo en aplicar la función {.arg replacement}.\"\n\n#: replace.R:209\nmsgid \"It must accept a character vector of any length.\"\nmsgstr \"Debe aceptar un vector de caracteres de cualquier longitud.\"\n\n#: replace.R:220\nmsgid \"\"\n\"{.arg replacement} function must return a character vector, not {.\"\n\"obj_type_friendly {new_flat}}.\"\nmsgstr \"\"\n\"La función {.arg replacement} debe devolver un vector de caracteres, no {.\"\n\"obj_type_friendly {new_flat}}.\"\n\n#: replace.R:226\nmsgid \"\"\n\"{.arg replacement} function must return a vector the same length as the input \"\n\"({length(old_flat)}), not length {length(new_flat)}.\"\nmsgstr \"\"\n\"La función {.arg replacement} debe devolver un vector del mismo largo que el input \"\n\"({length(old_flat)}), no de {length(new_flat)} de largo.\"\n\n#: split.R:122\nmsgid \"{.arg i} must not be 0.\"\nmsgstr \"{.arg i} no debe ser igual a 0.\"\n\n#: trunc.R:32\nmsgid \"`width` ({width}) is shorter than `ellipsis` ({str_length(ellipsis)}).\"\nmsgstr \"`width` ({width}) es más corto que `ellipsis` ({str_length(ellipsis)}).\"\n\n#: utils.R:23\nmsgid \"{.arg pattern} can't be a boundary.\"\nmsgstr \"{.arg pattern} no puede ser un límite.\"\n\n#: utils.R:26\nmsgid \"{.arg pattern} can't be the empty string ({.code \\\"\\\"}).\"\nmsgstr \"{.arg pattern} no puede ser una cadena de caracteres vacia ({.code \\\"\\\"}).\"\n"
  },
  {
    "path": "po/R-stringr.pot",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: stringr 1.5.1.9000\\n\"\n\"POT-Creation-Date: 2024-08-15 10:19-0700\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: detect.R:141\nmsgid \"{.arg pattern} must be a plain string, not a stringr modifier.\"\nmsgstr \"\"\n\n#: interp.R:105\nmsgid \"Invalid template string for interpolation.\"\nmsgstr \"\"\n\n#: interp.R:176\nmsgid \"Failed to parse input {.str {text}}\"\nmsgstr \"\"\n\n#: match.R:54 match.R:68\nmsgid \"{.arg pattern} must be a regular expression.\"\nmsgstr \"\"\n\n#: modifiers.R:216\nmsgid \"{.arg pattern} must be a string, not {.obj_type_friendly {x}}.\"\nmsgstr \"\"\n\n#: replace.R:208\nmsgid \"Failed to apply {.arg replacement} function.\"\nmsgstr \"\"\n\n#: replace.R:209\nmsgid \"It must accept a character vector of any length.\"\nmsgstr \"\"\n\n#: replace.R:220\nmsgid \"\"\n\"{.arg replacement} function must return a character vector, not {.\"\n\"obj_type_friendly {new_flat}}.\"\nmsgstr \"\"\n\n#: replace.R:226\nmsgid \"\"\n\"{.arg replacement} function must return a vector the same length as the \"\n\"input ({length(old_flat)}), not length {length(new_flat)}.\"\nmsgstr \"\"\n\n#: split.R:122\nmsgid \"{.arg i} must not be 0.\"\nmsgstr \"\"\n\n#: trunc.R:32\nmsgid \"`width` ({width}) is shorter than `ellipsis` ({str_length(ellipsis)}).\"\nmsgstr \"\"\n\n#: utils.R:23\nmsgid \"{.arg pattern} can't be a boundary.\"\nmsgstr \"\"\n\n#: utils.R:26\nmsgid \"{.arg pattern} can't be the empty string ({.code \\\"\\\"}).\"\nmsgstr \"\"\n"
  },
  {
    "path": "revdep/.gitignore",
    "content": "checks\nlibrary\nchecks.noindex\nlibrary.noindex\ndata.sqlite\n*.html\ncloud.noindex\n"
  },
  {
    "path": "revdep/README.md",
    "content": "# Revdeps\n\n## Failed to check (2)\n\n|package             |version |error |warning |note |\n|:-------------------|:-------|:-----|:-------|:----|\n|DSMolgenisArmadillo |?       |      |        |     |\n|multinma            |0.8.1   |1     |        |     |\n\n## New problems (9)\n\n|package   |version |error  |warning |note |\n|:---------|:-------|:------|:-------|:----|\n|[huxtable](problems.md#huxtable)|5.7.0   |__+2__ |        |1    |\n|[latex2exp](problems.md#latex2exp)|0.9.6   |__+2__ |        |     |\n|[NMsim](problems.md#nmsim)|0.2.5   |__+1__ |        |     |\n|[nrlR](problems.md#nrlr)|0.1.1   |__+1__ |        |     |\n|[phenofit](problems.md#phenofit)|0.3.10  |__+2__ |        |     |\n|[psycModel](problems.md#psycmodel)|0.5.0   |__+1__ |        |1    |\n|[salty](problems.md#salty)|0.1.1   |__+2__ |        |     |\n|[sdbuildR](problems.md#sdbuildr)|1.0.7   |__+1__ |        |     |\n|[zipangu](problems.md#zipangu)|0.3.3   |__+1__ |        |1    |\n\n"
  },
  {
    "path": "revdep/cran.md",
    "content": "## revdepcheck results\n\nWe checked 2390 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package.\n\n * We saw 9 new problems\n * We failed to check 2 packages\n\nIssues with CRAN packages are summarised below.\n\n### New problems\n(This reports the first line of each new failure)\n\n* huxtable\n  checking examples ... ERROR\n  checking tests ... ERROR\n\n* latex2exp\n  checking tests ... ERROR\n  checking re-building of vignette outputs ... ERROR\n\n* NMsim\n  checking tests ... ERROR\n\n* nrlR\n  checking examples ... ERROR\n\n* phenofit\n  checking examples ... ERROR\n  checking tests ... ERROR\n\n* psycModel\n  checking tests ... ERROR\n\n* salty\n  checking examples ... ERROR\n  checking tests ... ERROR\n\n* sdbuildR\n  checking tests ... ERROR\n\n* zipangu\n  checking tests ... ERROR\n\n### Failed to check\n\n* DSMolgenisArmadillo (NA)\n* multinma            (NA)\n"
  },
  {
    "path": "revdep/email.yml",
    "content": "release_date: ???\nrel_release_date: ???\nmy_news_url: ???\nrelease_version: ???\nrelease_details: ???\n"
  },
  {
    "path": "revdep/failures.md",
    "content": "# DSMolgenisArmadillo (3.0.1)\n\n* GitHub: <https://github.com/molgenis/molgenis-r-datashield>\n* Email: <mailto:m.k.slofstra@umcg.nl>\n* GitHub mirror: <https://github.com/cran/DSMolgenisArmadillo>\n\nRun `revdepcheck::cloud_details(, \"DSMolgenisArmadillo\")` for more info\n\n## Error before installation\n\n### Devel\n\n```\n* using log directory ‘/tmp/workdir/DSMolgenisArmadillo/new/DSMolgenisArmadillo.Rcheck’\n* using R version 4.5.1 (2025-06-13)\n* using platform: x86_64-pc-linux-gnu\n* R was compiled by\n    gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0\n    GNU Fortran (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0\n* running under: Ubuntu 24.04.3 LTS\n* using session charset: UTF-8\n* using option ‘--no-manual’\n* checking for file ‘DSMolgenisArmadillo/DESCRIPTION’ ... OK\n...\n* checking files in ‘vignettes’ ... OK\n* checking examples ... OK\n* checking for unstated dependencies in ‘tests’ ... OK\n* checking tests ... OK\n  Running ‘testthat.R’\n* checking for unstated dependencies in vignettes ... OK\n* checking package vignettes ... OK\n* checking re-building of vignette outputs ... OK\n* DONE\nStatus: OK\n\n\n\n\n\n```\n### CRAN\n\n```\n* using log directory ‘/tmp/workdir/DSMolgenisArmadillo/old/DSMolgenisArmadillo.Rcheck’\n* using R version 4.5.1 (2025-06-13)\n* using platform: x86_64-pc-linux-gnu\n* R was compiled by\n    gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0\n    GNU Fortran (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0\n* running under: Ubuntu 24.04.3 LTS\n* using session charset: UTF-8\n* using option ‘--no-manual’\n* checking for file ‘DSMolgenisArmadillo/DESCRIPTION’ ... OK\n...\n* checking files in ‘vignettes’ ... OK\n* checking examples ... OK\n* checking for unstated dependencies in ‘tests’ ... OK\n* checking tests ... OK\n  Running ‘testthat.R’\n* checking for unstated dependencies in vignettes ... OK\n* checking package vignettes ... OK\n* checking re-building of vignette outputs ... OK\n* DONE\nStatus: OK\n\n\n\n\n\n```\n# multinma (0.8.1)\n\n* GitHub: <https://github.com/dmphillippo/multinma>\n* Email: <mailto:david.phillippo@bristol.ac.uk>\n* GitHub mirror: <https://github.com/cran/multinma>\n\nRun `revdepcheck::cloud_details(, \"multinma\")` for more info\n\n## In both\n\n*   checking whether package ‘multinma’ can be installed ... ERROR\n     ```\n     Installation failed.\n     See ‘/tmp/workdir/multinma/new/multinma.Rcheck/00install.out’ for details.\n     ```\n\n## Installation\n\n### Devel\n\n```\n* installing *source* package ‘multinma’ ...\n** this is package ‘multinma’ version ‘0.8.1’\n** package ‘multinma’ successfully unpacked and MD5 sums checked\n** using staged installation\n** libs\nusing C++ compiler: ‘g++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0’\nusing C++17\n\n\ng++ -std=gnu++17 -I\"/opt/R/4.5.1/lib/R/include\" -DNDEBUG -I\"../inst/include\" -I\"/usr/local/lib/R/site-library/StanHeaders/include/src\" -DBOOST_DISABLE_ASSERTS -DEIGEN_NO_DEBUG -DBOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error -DUSE_STANC3 -D_HAS_AUTO_PTR_ETC=0 -I'/usr/local/lib/R/site-library/BH/include' -I'/usr/local/lib/R/site-library/Rcpp/include' -I'/usr/local/lib/R/site-library/RcppEigen/include' -I'/usr/local/lib/R/site-library/RcppParallel/include' -I'/usr/local/lib/R/site-library/rstan/include' -I'/usr/local/lib/R/site-library/StanHeaders/include' -I/usr/local/include    -I'/usr/local/lib/R/site-library/RcppParallel/include' -D_REENTRANT -DSTAN_THREADS   -fpic  -g -O2   -c RcppExports.cpp -o RcppExports.o\n...\n/usr/local/lib/R/site-library/StanHeaders/include/src/stan/mcmc/hmc/hamiltonians/dense_e_metric.hpp:22:0:   required from ‘double stan::mcmc::dense_e_metric<Model, BaseRNG>::T(stan::mcmc::dense_e_point&) [with Model = model_survival_param_namespace::model_survival_param; BaseRNG = boost::random::additive_combine_engine<boost::random::linear_congruential_engine<unsigned int, 40014, 0, 2147483563>, boost::random::linear_congruential_engine<unsigned int, 40692, 0, 2147483399> >]’\n/usr/local/lib/R/site-library/StanHeaders/include/src/stan/mcmc/hmc/hamiltonians/dense_e_metric.hpp:21:0:   required from here\n/usr/local/lib/R/site-library/RcppEigen/include/Eigen/src/Core/DenseCoeffsBase.h:654:74: warning: ignoring attributes on template argument ‘Eigen::internal::packet_traits<double>::type’ {aka ‘__m128d’} [-Wignored-attributes]\n  654 |   return internal::first_aligned<int(unpacket_traits<DefaultPacketType>::alignment),Derived>(m);\n      |                                                                          ^~~~~~~~~\ng++: fatal error: Killed signal terminated program cc1plus\ncompilation terminated.\nmake: *** [/opt/R/4.5.1/lib/R/etc/Makeconf:209: stanExports_survival_param.o] Error 1\nERROR: compilation failed for package ‘multinma’\n* removing ‘/tmp/workdir/multinma/new/multinma.Rcheck/multinma’\n\n\n```\n### CRAN\n\n```\n* installing *source* package ‘multinma’ ...\n** this is package ‘multinma’ version ‘0.8.1’\n** package ‘multinma’ successfully unpacked and MD5 sums checked\n** using staged installation\n** libs\nusing C++ compiler: ‘g++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0’\nusing C++17\n\n\ng++ -std=gnu++17 -I\"/opt/R/4.5.1/lib/R/include\" -DNDEBUG -I\"../inst/include\" -I\"/usr/local/lib/R/site-library/StanHeaders/include/src\" -DBOOST_DISABLE_ASSERTS -DEIGEN_NO_DEBUG -DBOOST_MATH_OVERFLOW_ERROR_POLICY=errno_on_error -DUSE_STANC3 -D_HAS_AUTO_PTR_ETC=0 -I'/usr/local/lib/R/site-library/BH/include' -I'/usr/local/lib/R/site-library/Rcpp/include' -I'/usr/local/lib/R/site-library/RcppEigen/include' -I'/usr/local/lib/R/site-library/RcppParallel/include' -I'/usr/local/lib/R/site-library/rstan/include' -I'/usr/local/lib/R/site-library/StanHeaders/include' -I/usr/local/include    -I'/usr/local/lib/R/site-library/RcppParallel/include' -D_REENTRANT -DSTAN_THREADS   -fpic  -g -O2   -c RcppExports.cpp -o RcppExports.o\n...\n/usr/local/lib/R/site-library/StanHeaders/include/src/stan/mcmc/hmc/hamiltonians/dense_e_metric.hpp:22:0:   required from ‘double stan::mcmc::dense_e_metric<Model, BaseRNG>::T(stan::mcmc::dense_e_point&) [with Model = model_survival_param_namespace::model_survival_param; BaseRNG = boost::random::additive_combine_engine<boost::random::linear_congruential_engine<unsigned int, 40014, 0, 2147483563>, boost::random::linear_congruential_engine<unsigned int, 40692, 0, 2147483399> >]’\n/usr/local/lib/R/site-library/StanHeaders/include/src/stan/mcmc/hmc/hamiltonians/dense_e_metric.hpp:21:0:   required from here\n/usr/local/lib/R/site-library/RcppEigen/include/Eigen/src/Core/DenseCoeffsBase.h:654:74: warning: ignoring attributes on template argument ‘Eigen::internal::packet_traits<double>::type’ {aka ‘__m128d’} [-Wignored-attributes]\n  654 |   return internal::first_aligned<int(unpacket_traits<DefaultPacketType>::alignment),Derived>(m);\n      |                                                                          ^~~~~~~~~\ng++: fatal error: Killed signal terminated program cc1plus\ncompilation terminated.\nmake: *** [/opt/R/4.5.1/lib/R/etc/Makeconf:209: stanExports_survival_param.o] Error 1\nERROR: compilation failed for package ‘multinma’\n* removing ‘/tmp/workdir/multinma/old/multinma.Rcheck/multinma’\n\n\n```\n"
  },
  {
    "path": "revdep/problems.md",
    "content": "# huxtable (5.7.0)\n\n* GitHub: <https://github.com/hughjonesd/huxtable>\n* Email: <mailto:davidhughjones@gmail.com>\n* GitHub mirror: <https://github.com/cran/huxtable>\n\nRun `revdepcheck::cloud_details(, \"huxtable\")` for more info\n\n## Newly broken\n\n*   checking examples ... ERROR\n     ```\n     ...\n       2. ├─huxtable:::print.huxtable(x)\n       3. │ └─huxtable (local) meth(x, ...)\n       4. │   ├─base::cat(to_screen(ht, ...))\n       5. │   └─huxtable::to_screen(ht, ...)\n       6. │     └─huxtable:::generate_table_display(...)\n       7. │       └─huxtable:::create_character_matrix(...)\n       8. │         └─huxtable:::character_matrix(...)\n       9. │           └─huxtable:::prepare_cell_display_data(ht, markdown)\n      10. │             └─huxtable:::clean_contents(ht, output_type = if (markdown) \"markdown\" else \"screen\")\n      11. │               └─huxtable:::format_numbers_matrix(contents, ht)\n      12. │                 └─base::vapply(...)\n      13. │                   └─huxtable (local) FUN(X[[i]], ...)\n      14. │                     └─base::vapply(...)\n      15. │                       └─huxtable (local) FUN(X[[i]], ...)\n      16. │                         └─huxtable:::format_numbers(cell, nf[[row, col]])\n      17. │                           └─stringr::str_replace_all(string, number_regex(), format_numeral)\n      18. │                             └─stringr:::str_transform_all(string, pattern, replacement)\n      19. │                               ├─base::withCallingHandlers(...)\n      20. │                               └─huxtable (local) replacement(old_flat)\n      21. │                                 └─numeral_formatter(num_fmt)(num)\n      22. └─base::.handleSimpleError(...)\n      23.   └─stringr (local) h(simpleError(msg, call))\n      24.     └─cli::cli_abort(...)\n      25.       └─rlang::abort(...)\n     Execution halted\n     ```\n\n*   checking tests ... ERROR\n     ```\n     ...\n       • x86_64-w64-mingw32/x64/validate-outputs/dimensions.rtf\n       • x86_64-w64-mingw32/x64/validate-outputs/dimensions.tex\n       • x86_64-w64-mingw32/x64/validate-outputs/dimensions.txt\n       • x86_64-w64-mingw32/x64/validate-outputs/table_caption_tests.html\n       • x86_64-w64-mingw32/x64/validate-outputs/table_caption_tests.rtf\n       • x86_64-w64-mingw32/x64/validate-outputs/table_caption_tests.tex\n       • x86_64-w64-mingw32/x64/validate-outputs/table_caption_tests.txt\n       • x86_64-w64-mingw32/x64/validate-outputs/table_width_tests.html\n       • x86_64-w64-mingw32/x64/validate-outputs/table_width_tests.rtf\n       • x86_64-w64-mingw32/x64/validate-outputs/table_width_tests.tex\n       • x86_64-w64-mingw32/x64/validate-outputs/table_width_tests.txt\n       • x86_64-w64-mingw32/x64/validate-outputs/text_alignment.html\n       • x86_64-w64-mingw32/x64/validate-outputs/text_alignment.rtf\n       • x86_64-w64-mingw32/x64/validate-outputs/text_alignment.tex\n       • x86_64-w64-mingw32/x64/validate-outputs/text_alignment.txt\n       • x86_64-w64-mingw32/x64/validate-outputs/text_effects.html\n       • x86_64-w64-mingw32/x64/validate-outputs/text_effects.rtf\n       • x86_64-w64-mingw32/x64/validate-outputs/text_effects.tex\n       • x86_64-w64-mingw32/x64/validate-outputs/text_effects.txt\n       • x86_64-w64-mingw32/x64/validate-outputs/text_properties.html\n       • x86_64-w64-mingw32/x64/validate-outputs/text_properties.rtf\n       • x86_64-w64-mingw32/x64/validate-outputs/text_properties.tex\n       • x86_64-w64-mingw32/x64/validate-outputs/text_properties.txt\n       Error: Test failures\n       Execution halted\n     ```\n\n## In both\n\n*   checking dependencies in R code ... NOTE\n     ```\n     Namespaces in Imports field not imported from:\n       ‘R6’ ‘xml2’\n       All declared Imports should be used.\n     ```\n\n# latex2exp (0.9.6)\n\n* GitHub: <https://github.com/stefano-meschiari/latex2exp>\n* Email: <mailto:stefano.meschiari@gmail.com>\n* GitHub mirror: <https://github.com/cran/latex2exp>\n\nRun `revdepcheck::cloud_details(, \"latex2exp\")` for more info\n\n## Newly broken\n\n*   checking tests ... ERROR\n     ```\n     ...\n       (2), not length 1.\n       Backtrace:\n            ▆\n         1. ├─latex2exp:::expect_renders_same(...) at test_simple.R:166:3\n         2. │ └─latex2exp:::.expect_renders(object, expected_expression, negate = FALSE) at tests/testthat/setup.R:30:3\n         3. │   └─latex2exp::TeX(act$val) at tests/testthat/setup.R:65:5\n         4. │     └─latex2exp:::parse_latex(input)\n         5. │       └─... %>% ...\n         6. ├─stringr::str_replace_all(., \"([^\\\\\\\\]?)\\\\\\\\\\\\s\", \"\\\\1\\\\\\\\@SPACE2{}\")\n         7. │ └─stringr:::check_lengths(string, pattern, replacement)\n         8. │   └─vctrs::vec_size_common(...)\n         9. ├─stringr::str_replace_all(., \"([^\\\\\\\\]?)\\\\\\\\;\", \"\\\\1\\\\\\\\@SPACE2{}\")\n        10. │ └─stringr:::check_lengths(string, pattern, replacement)\n        11. │   └─vctrs::vec_size_common(...)\n        12. ├─stringr::str_replace_all(., \"([^\\\\\\\\]?)\\\\\\\\,\", \"\\\\1\\\\\\\\@SPACE1{}\")\n        13. │ └─stringr:::check_lengths(string, pattern, replacement)\n        14. │   └─vctrs::vec_size_common(...)\n        15. └─stringr::str_replace_all(...)\n        16.   └─stringr:::str_transform_all(string, pattern, replacement)\n        17.     └─cli::cli_abort(...)\n        18.       └─rlang::abort(...)\n       \n       [ FAIL 1 | WARN 1 | SKIP 0 | PASS 100 ]\n       Error: Test failures\n       Execution halted\n     ```\n\n*   checking re-building of vignette outputs ... ERROR\n     ```\n     Error(s) in re-building vignettes:\n     --- re-building ‘supported-commands.Rmd’ using rmarkdown\n     --- finished re-building ‘supported-commands.Rmd’\n     \n     --- re-building ‘using-latex2exp.Rmd’ using rmarkdown\n     ```\n\n# NMsim (0.2.5)\n\n* GitHub: <https://github.com/nmautoverse/NMsim>\n* Email: <mailto:philip@delff.dk>\n* GitHub mirror: <https://github.com/cran/NMsim>\n\nRun `revdepcheck::cloud_details(, \"NMsim\")` for more info\n\n## Newly broken\n\n*   checking tests ... ERROR\n     ```\n     ...\n     Running the tests in ‘tests/testthat.R’ failed.\n     Complete output:\n       > library(testthat)\n       > library(NMsim)\n       NMsim 0.2.5. Browse NMsim documentation at\n       https://NMautoverse.github.io/NMsim/\n       > \n       > test_check(\"NMsim\")\n       [ FAIL 1 | WARN 0 | SKIP 0 | PASS 168 ]\n       \n       ══ Failed tests ════════════════════════════════════════════════════════════════\n       ── Error ('test_NMsim_VarCov.R:62:5'): Basic ───────────────────────────────────\n       Error in `stringr::str_replace_all(mod$THETA, \"\\\\d+\\\\.\\\\d+\", function(x) round(as.numeric(x), \n           digits = 3))`: `replacement` function must return a character vector, not a double\n       vector.\n       Backtrace:\n           ▆\n        1. └─stringr::str_replace_all(...) at test_NMsim_VarCov.R:62:5\n        2.   └─stringr:::str_transform_all(string, pattern, replacement)\n        3.     └─cli::cli_abort(...)\n        4.       └─rlang::abort(...)\n       \n       [ FAIL 1 | WARN 0 | SKIP 0 | PASS 168 ]\n       Error: Test failures\n       Execution halted\n     ```\n\n# nrlR (0.1.1)\n\n* Email: <mailto:danieltomaro@icloud.com>\n* GitHub mirror: <https://github.com/cran/nrlR>\n\nRun `revdepcheck::cloud_details(, \"nrlR\")` for more info\n\n## Newly broken\n\n*   checking examples ... ERROR\n     ```\n     ...\n     > ### Name: fetch_lineups\n     > ### Title: Fetch NRL Team Lineups\n     > ### Aliases: fetch_lineups\n     > \n     > ### ** Examples\n     > \n     > fetch_lineups(url = \"https://www.nrl.com/news/2024/05/07/nrl-team-lists-round-10/\")\n     Fetching team lineups from\n     https://www.nrl.com/news/2024/05/07/nrl-team-lists-round-10/\n     Error in `stringr::str_replace()`:\n     ! `pattern` can not contain NAs.\n     Backtrace:\n          ▆\n       1. └─nrlR::fetch_lineups(url = \"https://www.nrl.com/news/2024/05/07/nrl-team-lists-round-10/\")\n       2.   ├─stringr::str_squish(...)\n       3.   │ └─stringr:::copy_names(...)\n       4.   ├─stringr::str_replace(...)\n       5.   │ └─stringr:::check_lengths(string, pattern, replacement)\n       6.   │   └─vctrs::vec_size_common(...)\n       7.   └─stringr::str_replace(rvest::html_text2(home_node), home_role_full, \"\")\n       8.     ├─stringr:::type(pattern)\n       9.     └─stringr:::type.character(pattern)\n      10.       └─cli::cli_abort(tr_(\"{.arg pattern} can not contain NAs.\"), call = error_call)\n      11.         └─rlang::abort(...)\n     Execution halted\n     ```\n\n# phenofit (0.3.10)\n\n* GitHub: <https://github.com/eco-hydro/phenofit>\n* Email: <mailto:kongdd.sysu@gmail.com>\n* GitHub mirror: <https://github.com/cran/phenofit>\n\nRun `revdepcheck::cloud_details(, \"phenofit\")` for more info\n\n## Newly broken\n\n*   checking examples ... ERROR\n     ```\n     ...\n       3. │ └─... %>% set_names(dt$flag)\n       4. ├─dplyr::group_map(...)\n       5. ├─dplyr:::group_map.data.frame(...)\n       6. │ └─dplyr:::map2(chunks, group_keys, .f, ...)\n       7. │   └─base::mapply(.f, .x, .y, MoreArgs = list(...), SIMPLIFY = FALSE)\n       8. │     └─phenofit (local) `<fn>`(dots[[1L]][[1L]], dots[[2L]][[1L]])\n       9. │       └─phenofit:::PhenoDeriv.default(values, t, der1, IsPlot = FALSE)\n      10. │         └─phenofit::findpeaks(...)\n      11. │           └─xc %<>% str_replace_midzero()\n      12. ├─phenofit:::str_replace_midzero(.)\n      13. │ └─str_replace_all(x, \"\\\\++0\\\\++\", . %>% replace(\"+\")) %>% ...\n      14. ├─stringr::str_replace_all(., \"-+0-+\", . %>% replace(\"-\"))\n      15. │ └─stringr:::str_transform_all(string, pattern, replacement)\n      16. │   ├─base::withCallingHandlers(...)\n      17. │   └─magrittr (local) replacement(old_flat)\n      18. │     └─magrittr::freduce(value, `_function_list`)\n      19. │       ├─base::withVisible(function_list[[k]](value))\n      20. │       └─function_list[[k]](value)\n      21. │         └─phenofit (local) replace(., \"-\")\n      22. │           └─base::paste(rep(replacement, nchar(x)), collapse = \"\")\n      23. └─base::.handleSimpleError(...)\n      24.   └─stringr (local) h(simpleError(msg, call))\n      25.     └─cli::cli_abort(...)\n      26.       └─rlang::abort(...)\n     Execution halted\n     ```\n\n*   checking tests ... ERROR\n     ```\n     ...\n         8. │   └─rlang::eval_bare(quo_get_expr(.quo), quo_get_env(.quo))\n         9. ├─base::do.call(season, param)\n        10. ├─phenofit (local) `<fn>`(...)\n        11. │ └─phenofit:::findpeaks_season(...)\n        12. │   └─phenofit::findpeaks(...)\n        13. │     └─xc %<>% str_replace_midzero()\n        14. ├─phenofit:::str_replace_midzero(.)\n        15. │ └─str_replace_all(x, \"\\\\++0\\\\++\", . %>% replace(\"+\")) %>% ...\n        16. ├─stringr::str_replace_all(., \"-+0-+\", . %>% replace(\"-\"))\n        17. │ └─stringr:::str_transform_all(string, pattern, replacement)\n        18. │   ├─base::withCallingHandlers(...)\n        19. │   └─magrittr (local) replacement(old_flat)\n        20. │     └─magrittr::freduce(value, `_function_list`)\n        21. │       ├─base::withVisible(function_list[[k]](value))\n        22. │       └─function_list[[k]](value)\n        23. │         └─phenofit (local) replace(., \"-\")\n        24. │           └─base::paste(rep(replacement, nchar(x)), collapse = \"\")\n        25. └─base::.handleSimpleError(...)\n        26.   └─stringr (local) h(simpleError(msg, call))\n        27.     └─cli::cli_abort(...)\n        28.       └─rlang::abort(...)\n       \n       [ FAIL 2 | WARN 2 | SKIP 0 | PASS 66 ]\n       Error: Test failures\n       Execution halted\n     ```\n\n# psycModel (0.5.0)\n\n* GitHub: <https://github.com/jasonmoy28/psycModel>\n* Email: <mailto:jasonmoy28@gmail.com>\n* GitHub mirror: <https://github.com/cran/psycModel>\n\nRun `revdepcheck::cloud_details(, \"psycModel\")` for more info\n\n## Newly broken\n\n*   checking tests ... ERROR\n     ```\n     ...\n       \n       \n       \n       \n       \n       \n       \n       \n       [ FAIL 2 | WARN 0 | SKIP 0 | PASS 68 ]\n       \n       ══ Failed tests ════════════════════════════════════════════════════════════════\n       ── Failure ('test-model-table.R:15:3'): model_table: linear regression ─────────\n       `lm_1_check` (`actual`) not equal to model_summary[[2]] (`expected`).\n       \n       `names(actual)`:   \"(Intercept)\" \"Sepal.Length\"\n       `names(expected)`: \"\"            \"\"            \n       ── Failure ('test-model-table.R:16:3'): model_table: linear regression ─────────\n       `lm_2_check` (`actual`) not equal to model_summary[[3]] (`expected`).\n       \n       `names(actual)`:   \"(Intercept)\" \"Petal.Length\"\n       `names(expected)`: \"\"            \"\"            \n       \n       [ FAIL 2 | WARN 0 | SKIP 0 | PASS 68 ]\n       Error: Test failures\n       Execution halted\n     ```\n\n## In both\n\n*   checking dependencies in R code ... NOTE\n     ```\n     Namespaces in Imports field not imported from:\n       ‘lifecycle’ ‘patchwork’\n       All declared Imports should be used.\n     ```\n\n# salty (0.1.1)\n\n* GitHub: <https://github.com/mdlincoln/salty>\n* Email: <mailto:matthew.d.lincoln@gmail.com>\n* GitHub mirror: <https://github.com/cran/salty>\n\nRun `revdepcheck::cloud_details(, \"salty\")` for more info\n\n## Newly broken\n\n*   checking examples ... ERROR\n     ```\n     ...\n     > x <- c(\"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\",\n     +        \"Nunc finibus tortor a elit eleifend interdum.\",\n     +        \"Maecenas aliquam augue sit amet ultricies placerat.\")\n     > \n     > salt_replace(x, replacement_shaker$capitalization, p = 0.5, rep_p = 0.2)\n     Error in `purrr::map2_chr()`:\n     ℹ In index: 1.\n     Caused by error in `stringr::str_replace_all()`:\n     ! `replacement` function must return a vector the same length as the\n       input (47), not length 1.\n     Backtrace:\n          ▆\n       1. └─salty::salt_replace(...)\n       2.   └─purrr::map2_chr(...)\n       3.     └─purrr:::map2_(\"character\", .x, .y, .f, ..., .progress = .progress)\n       4.       ├─purrr:::with_indexed_errors(...)\n       5.       │ └─base::withCallingHandlers(...)\n       6.       ├─purrr:::call_with_cleanup(...)\n       7.       └─salty (local) .f(.x[[i]], .y[[i]], ...)\n       8.         └─salty:::selective_replacement(xc, replacements(i = si), rep_p)\n       9.           └─stringr::str_replace_all(x, pattern = patterns, replacement = repfun)\n      10.             └─stringr:::str_transform_all(string, pattern, replacement)\n      11.               └─cli::cli_abort(...)\n      12.                 └─rlang::abort(...)\n     Execution halted\n     ```\n\n*   checking tests ... ERROR\n     ```\n     ...\n         9. │         └─purrr::map2_chr(...)\n        10. │           └─purrr:::map2_(\"character\", .x, .y, .f, ..., .progress = .progress)\n        11. │             ├─purrr:::with_indexed_errors(...)\n        12. │             │ └─base::withCallingHandlers(...)\n        13. │             ├─purrr:::call_with_cleanup(...)\n        14. │             └─salty (local) .f(.x[[i]], .y[[i]], ...)\n        15. │               └─salty:::selective_replacement(xc, replacements(i = si), rep_p)\n        16. │                 └─stringr::str_replace_all(x, pattern = patterns, replacement = repfun)\n        17. │                   └─stringr:::str_transform_all(string, pattern, replacement)\n        18. │                     └─cli::cli_abort(...)\n        19. │                       └─rlang::abort(...)\n        20. │                         └─rlang:::signal_abort(cnd, .file)\n        21. │                           └─base::signalCondition(cnd)\n        22. ├─purrr (local) `<fn>`(`<rlng_rrr>`)\n        23. │ └─cli::cli_abort(...)\n        24. │   └─rlang::abort(...)\n        25. │     └─rlang:::signal_abort(cnd, .file)\n        26. │       └─base::signalCondition(cnd)\n        27. └─purrr (local) `<fn>`(`<prrr_rr_>`)\n        28.   └─cli::cli_abort(...)\n        29.     └─rlang::abort(...)\n       \n       [ FAIL 5 | WARN 0 | SKIP 0 | PASS 755 ]\n       Error: Test failures\n       Execution halted\n     ```\n\n# sdbuildR (1.0.7)\n\n* GitHub: <https://github.com/KCEvers/sdbuildR>\n* Email: <mailto:kyra.c.evers@gmail.com>\n* GitHub mirror: <https://github.com/cran/sdbuildR>\n\nRun `revdepcheck::cloud_details(, \"sdbuildR\")` for more info\n\n## Newly broken\n\n*   checking tests ... ERROR\n     ```\n     ...\n        12.     └─cli::cli_abort(...)\n        13.       └─rlang::abort(...)\n       ── Error ('test-conv_julia.R:723:3'): adding scientific notation ───────────────\n       Error in `stringr::str_replace_all(eqn, pattern = pattern, replacement = reformat_scientific)`: Failed to apply `replacement` function.\n       i It must accept a character vector of any length.\n       Caused by error in `if (nchar(format(num, scientific = FALSE)) > digits_max) ...`:\n       ! the condition has length > 1\n       Backtrace:\n            ▆\n         1. ├─testthat::expect_equal(...) at test-conv_julia.R:723:3\n         2. │ └─testthat::quasi_label(enquo(object), label, arg = \"object\")\n         3. │   └─rlang::eval_bare(expr, quo_get_env(quo))\n         4. ├─sdbuildR:::scientific_notation(\"hiding 1e+23\", task = \"add\")\n         5. │ └─stringr::str_replace_all(eqn, pattern = pattern, replacement = reformat_scientific)\n         6. │   └─stringr:::str_transform_all(string, pattern, replacement)\n         7. │     ├─base::withCallingHandlers(...)\n         8. │     └─sdbuildR (local) replacement(old_flat)\n         9. └─base::.handleSimpleError(...)\n        10.   └─stringr (local) h(simpleError(msg, call))\n        11.     └─cli::cli_abort(...)\n        12.       └─rlang::abort(...)\n       \n       [ FAIL 4 | WARN 0 | SKIP 30 | PASS 915 ]\n       Error: Test failures\n       Execution halted\n     ```\n\n# zipangu (0.3.3)\n\n* GitHub: <https://github.com/uribo/zipangu>\n* Email: <mailto:suika1127@gmail.com>\n* GitHub mirror: <https://github.com/cran/zipangu>\n\nRun `revdepcheck::cloud_details(, \"zipangu\")` for more info\n\n## Newly broken\n\n*   checking tests ... ERROR\n     ```\n     ...\n               res <- res %>% purrr::list_merge(city = split_pref[2] %>% \n                   dplyr::if_else(is_address_block(.), stringr::str_remove(., \n                       \"((土地区画|街区).+)\") %>% stringr::str_remove(\"土地区画|街区\"), \n                       .) %>% stringr::str_replace(\"(.市)(.+町.+)\", \n                   \"\\\\1\") %>% stringr::str_replace(city_name_regex, \n                   replacement = \"\\\\1\"))\n           }\n           else {\n               res <- res %>% purrr::list_merge(city = split_pref[2] %>% \n                   dplyr::if_else(is_address_block(.), stringr::str_remove(., \n                       \"((土地区画|街区).+)\") %>% stringr::str_remove(\"土地区画|街区\"), \n                       .) %>% stringr::str_replace(paste0(city_name_regex, \n                   \"(.+)\"), replacement = \"\\\\1\"))\n           }\n           res <- res %>% purrr::list_merge(street = split_pref[2] %>% \n               stringr::str_remove(res %>% purrr::pluck(\"city\")))\n           res %>% purrr::map(~dplyr::if_else(.x == \"\", NA_character_, \n               .x))\n       })`: ℹ In index: 1.\n       Caused by error in `str_replace()`:\n       ! `pattern` can not contain NAs.\n       \n       [ FAIL 1 | WARN 0 | SKIP 2 | PASS 143 ]\n       Error: Test failures\n       Execution halted\n     ```\n\n## In both\n\n*   checking DESCRIPTION meta-information ... NOTE\n     ```\n       Missing dependency on R >= 4.1.0 because package code uses the pipe\n       |> or function shorthand \\(...) syntax added in R 4.1.0.\n       File(s) using such syntax:\n         ‘convert-jyear-legacy.R’\n     ```\n\n"
  },
  {
    "path": "stringr.Rproj",
    "content": "Version: 1.0\n\nRestoreWorkspace: Default\nSaveWorkspace: Default\nAlwaysSaveHistory: Default\n\nEnableCodeIndexing: Yes\nUseSpacesForTab: Yes\nNumSpacesForTab: 2\nEncoding: UTF-8\n\nRnwWeave: Sweave\nLaTeX: pdfLaTeX\n\nAutoAppendNewline: Yes\nStripTrailingWhitespace: Yes\n\nBuildType: Package\nPackageUseDevtools: Yes\nPackageInstallArgs: --no-multiarch --with-keep.source\nPackageRoxygenize: rd,collate,namespace\n"
  },
  {
    "path": "tests/testthat/_snaps/c.md",
    "content": "# obeys tidyverse recycling rules\n\n    Code\n      str_c(c(\"x\", \"y\"), character())\n    Condition\n      Error in `str_c()`:\n      ! Can't recycle `..1` (size 2) to match `..2` (size 0).\n\n# vectorised arguments error\n\n    Code\n      str_c(letters, sep = c(\"a\", \"b\"))\n    Condition\n      Error in `str_c()`:\n      ! `sep` must be a single string, not a character vector.\n    Code\n      str_c(letters, collapse = c(\"a\", \"b\"))\n    Condition\n      Error in `str_c()`:\n      ! `collapse` must be a single string or `NULL`, not a character vector.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/conv.md",
    "content": "# check encoding argument\n\n    Code\n      str_conv(\"A\", c(\"ISO-8859-1\", \"ISO-8859-2\"))\n    Condition\n      Error in `str_conv()`:\n      ! `encoding` must be a single string, not a character vector.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/detect.md",
    "content": "# can't empty/boundary\n\n    Code\n      str_detect(\"x\", \"\")\n    Condition\n      Error in `str_detect()`:\n      ! `pattern` can't be the empty string (`\"\"`).\n    Code\n      str_starts(\"x\", \"\")\n    Condition\n      Error in `str_starts()`:\n      ! `pattern` can't be the empty string (`\"\"`).\n    Code\n      str_ends(\"x\", \"\")\n    Condition\n      Error in `str_ends()`:\n      ! `pattern` can't be the empty string (`\"\"`).\n\n# functions use tidyverse recycling rules\n\n    Code\n      str_detect(1:2, 1:3)\n    Condition\n      Error in `str_detect()`:\n      ! Can't recycle `string` (size 2) to match `pattern` (size 3).\n    Code\n      str_starts(1:2, 1:3)\n    Condition\n      Error in `str_starts()`:\n      ! Can't recycle `string` (size 2) to match `pattern` (size 3).\n    Code\n      str_ends(1:2, 1:3)\n    Condition\n      Error in `str_ends()`:\n      ! Can't recycle `string` (size 2) to match `pattern` (size 3).\n    Code\n      str_like(1:2, c(\"a\", \"b\", \"c\"))\n    Condition\n      Error in `str_like()`:\n      ! Can't recycle `string` (size 2) to match `pattern` (size 3).\n\n# str_like is case sensitive\n\n    Code\n      str_like(\"abc\", regex(\"x\"))\n    Condition\n      Error in `str_like()`:\n      ! `pattern` must be a plain string, not a stringr modifier.\n\n# ignore_case is deprecated but still respected\n\n    Code\n      out <- str_like(\"abc\", \"AB%\", ignore_case = TRUE)\n    Condition\n      Warning:\n      The `ignore_case` argument of `str_like()` is deprecated as of stringr 1.6.0.\n      i `str_like()` is always case sensitive.\n      i Use `str_ilike()` for case insensitive string matching.\n\n# str_ilike works\n\n    Code\n      str_ilike(\"abc\", regex(\"x\"))\n    Condition\n      Error in `str_ilike()`:\n      ! `pattern` must be a plain string, not a stringr modifier.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/dup.md",
    "content": "# separator must be a single string\n\n    Code\n      str_dup(\"a\", 3, sep = 1)\n    Condition\n      Error in `str_dup()`:\n      ! `sep` must be a single string or `NULL`, not the number 1.\n    Code\n      str_dup(\"a\", 3, sep = c(\"-\", \";\"))\n    Condition\n      Error in `str_dup()`:\n      ! `sep` must be a single string or `NULL`, not a character vector.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/equal.md",
    "content": "# vectorised using TRR\n\n    Code\n      str_equal(letters[1:3], c(\"a\", \"b\"))\n    Condition\n      Error in `str_equal()`:\n      ! Can't recycle `x` (size 3) to match `y` (size 2).\n\n"
  },
  {
    "path": "tests/testthat/_snaps/flatten.md",
    "content": "# collapse must be single string\n\n    Code\n      str_flatten(\"A\", c(\"a\", \"b\"))\n    Condition\n      Error in `str_flatten()`:\n      ! `collapse` must be a single string, not a character vector.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/interp.md",
    "content": "# str_interp fails when encountering nested placeholders\n\n    Code\n      str_interp(\"${${msg}}\")\n    Condition\n      Error in `str_interp()`:\n      ! Invalid template string for interpolation.\n    Code\n      str_interp(\"$[.2f]{${msg}}\")\n    Condition\n      Error in `str_interp()`:\n      ! Invalid template string for interpolation.\n\n# str_interp fails when input is not a character string\n\n    Code\n      str_interp(3L)\n    Condition\n      Error in `str_interp()`:\n      ! `string` must be a character vector, not the number 3.\n\n# str_interp wraps parsing errors\n\n    Code\n      str_interp(\"This is a ${1 +}\")\n    Condition\n      Error in `str_interp()`:\n      ! Failed to parse input \"1 +\"\n      Caused by error in `parse()`:\n      ! <text>:2:0: unexpected end of input\n      1: 1 +\n         ^\n\n"
  },
  {
    "path": "tests/testthat/_snaps/match.md",
    "content": "# match and match_all fail when pattern is not a regex\n\n    Code\n      str_match(phones, fixed(\"3\"))\n    Condition\n      Error in `str_match()`:\n      ! `pattern` must be a regular expression.\n    Code\n      str_match_all(phones, coll(\"9\"))\n    Condition\n      Error in `str_match_all()`:\n      ! `pattern` must be a regular expression.\n\n# match can't use other modifiers\n\n    Code\n      str_match(\"x\", coll(\"y\"))\n    Condition\n      Error in `str_match()`:\n      ! `pattern` must be a regular expression.\n    Code\n      str_match_all(\"x\", coll(\"y\"))\n    Condition\n      Error in `str_match_all()`:\n      ! `pattern` must be a regular expression.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/modifiers.md",
    "content": "# patterns coerced to character\n\n    Code\n      . <- regex(x)\n    Condition\n      Warning in `regex()`:\n      Coercing `pattern` to a plain character vector.\n    Code\n      . <- coll(x)\n    Condition\n      Warning in `coll()`:\n      Coercing `pattern` to a plain character vector.\n    Code\n      . <- fixed(x)\n    Condition\n      Warning in `fixed()`:\n      Coercing `pattern` to a plain character vector.\n\n# useful error message for bad type\n\n    Code\n      type(1:3)\n    Condition\n      Error:\n      ! `pattern` must be a character vector, not an integer vector.\n\n# useful errors for NAs\n\n    Code\n      type(NA)\n    Condition\n      Error:\n      ! `pattern` must be a character vector, not `NA`.\n    Code\n      type(c(\"a\", \"b\", NA_character_, \"c\"))\n    Condition\n      Error:\n      ! `pattern` can not contain NAs.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/replace.md",
    "content": "# replacement must be a string\n\n    Code\n      str_replace(\"x\", \"x\", 1)\n    Condition\n      Error in `str_replace()`:\n      ! `replacement` must be a character vector, not the number 1.\n\n# can't replace empty/boundary\n\n    Code\n      str_replace(\"x\", \"\", \"\")\n    Condition\n      Error in `str_replace()`:\n      ! `pattern` can't be the empty string (`\"\"`).\n    Code\n      str_replace(\"x\", boundary(\"word\"), \"\")\n    Condition\n      Error in `str_replace()`:\n      ! `pattern` can't be a boundary.\n    Code\n      str_replace_all(\"x\", \"\", \"\")\n    Condition\n      Error in `str_replace_all()`:\n      ! `pattern` can't be the empty string (`\"\"`).\n    Code\n      str_replace_all(\"x\", boundary(\"word\"), \"\")\n    Condition\n      Error in `str_replace_all()`:\n      ! `pattern` can't be a boundary.\n\n# useful error if not vectorised correctly\n\n    Code\n      str_replace_all(x, \"a|c\", ~ if (length(x) > 1) stop(\"Bad\"))\n    Condition\n      Error in `str_replace_all()`:\n      ! Failed to apply `replacement` function.\n      i It must accept a character vector of any length.\n      Caused by error in `replacement()`:\n      ! Bad\n\n# replacement function must return correct type/length\n\n    Code\n      str_replace_all(\"x\", \"x\", ~1)\n    Condition\n      Error in `str_replace_all()`:\n      ! `replacement` function must return a character vector, not a number.\n    Code\n      str_replace_all(\"x\", \"x\", ~ c(\"a\", \"b\"))\n    Condition\n      Error in `str_replace_all()`:\n      ! `replacement` function must return a vector the same length as the input (1), not length 2.\n\n# backrefs are correctly translated\n\n    Code\n      str_replace_all(\"abcde\", \"(b)(c)(d)\", \"\\\\4\")\n    Condition\n      Error in `stri_replace_all_regex()`:\n      ! Trying to access the index that is out of bounds. (U_INDEX_OUTOFBOUNDS_ERROR)\n\n"
  },
  {
    "path": "tests/testthat/_snaps/split.md",
    "content": "# str_split() checks its inputs\n\n    Code\n      str_split(letters[1:3], letters[1:2])\n    Condition\n      Error in `str_split()`:\n      ! Can't recycle `string` (size 3) to match `pattern` (size 2).\n    Code\n      str_split(\"x\", 1)\n    Condition\n      Error in `str_split()`:\n      ! `pattern` must be a character vector, not a number.\n    Code\n      str_split(\"x\", \"x\", n = 0)\n    Condition\n      Error in `str_split()`:\n      ! `n` must be a number larger than 1, not the number 0.\n\n# str_split_1 takes string and returns character vector\n\n    `string` must be a single string, not a character vector.\n\n# str_split_fixed check its inputs\n\n    Code\n      str_split_fixed(\"x\", \"x\", 0)\n    Condition\n      Error in `str_split_fixed()`:\n      ! `n` must be a number larger than 1, not the number 0.\n\n# str_split_i check its inputs\n\n    Code\n      str_split_i(\"x\", \"x\", 0)\n    Condition\n      Error in `str_split_i()`:\n      ! `i` must not be 0.\n    Code\n      str_split_i(\"x\", \"x\", 0.5)\n    Condition\n      Error in `str_split_i()`:\n      ! `i` must be a whole number, not the number 0.5.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/sub.md",
    "content": "# bad vectorisation gives informative error\n\n    Code\n      str_sub(x, 1:2, 1:3)\n    Condition\n      Error in `str_sub()`:\n      ! Can't recycle `string` (size 2) to match `end` (size 3).\n    Code\n      str_sub(x, 1:2, 1:2) <- 1:3\n    Condition\n      Error in `str_sub<-`:\n      ! Can't recycle `string` (size 2) to match `value` (size 3).\n\n"
  },
  {
    "path": "tests/testthat/_snaps/subset.md",
    "content": "# can't use boundaries\n\n    Code\n      str_subset(c(\"a\", \"b c\"), \"\")\n    Condition\n      Error in `str_subset()`:\n      ! `pattern` can't be the empty string (`\"\"`).\n    Code\n      str_subset(c(\"a\", \"b c\"), boundary())\n    Condition\n      Error in `str_subset()`:\n      ! `pattern` can't be a boundary.\n\n"
  },
  {
    "path": "tests/testthat/_snaps/trunc.md",
    "content": "# does not truncate to a length shorter than elipsis\n\n    Code\n      str_trunc(\"foobar\", 2)\n    Condition\n      Error in `str_trunc()`:\n      ! `width` (2) is shorter than `ellipsis` (3).\n    Code\n      str_trunc(\"foobar\", 3, ellipsis = \"....\")\n    Condition\n      Error in `str_trunc()`:\n      ! `width` (3) is shorter than `ellipsis` (4).\n\n"
  },
  {
    "path": "tests/testthat/_snaps/view.md",
    "content": "# results are truncated\n\n    Code\n      str_view(words)\n    Output\n       [1] | a\n       [2] | able\n       [3] | about\n       [4] | absolute\n       [5] | accept\n       [6] | account\n       [7] | achieve\n       [8] | across\n       [9] | act\n      [10] | active\n      [11] | actual\n      [12] | add\n      [13] | address\n      [14] | admit\n      [15] | advertise\n      [16] | affect\n      [17] | afford\n      [18] | after\n      [19] | afternoon\n      [20] | again\n      ... and 960 more\n\n---\n\n    Code\n      str_view(words)\n    Output\n      [1] | a\n      [2] | able\n      [3] | about\n      [4] | absolute\n      [5] | accept\n      ... and 975 more\n\n# indices come from original vector\n\n    Code\n      str_view(letters, \"a|z\", match = TRUE)\n    Output\n       [1] | <a>\n      [26] | <z>\n\n# view highlights all matches\n\n    Code\n      str_view(x, \"[aeiou]\")\n    Output\n      [1] | <a>bc\n      [2] | d<e>f\n    Code\n      str_view(x, \"d|e\")\n    Output\n      [2] | <d><e>f\n\n# view highlights whitespace (except a space/nl)\n\n    Code\n      str_view(x)\n    Output\n      [1] |  \n      [2] | {\\u00a0}\n      [3] | \n          | \n      [4] | {\\t}\n    Code\n      # or can instead use escapes\n      str_view(x, use_escapes = TRUE)\n    Output\n      [1] |  \n      [2] | \\u00a0\n      [3] | \\n\n      [4] | \\t\n\n# view displays message for empty vectors\n\n    Code\n      str_view(character())\n    Message\n      x Empty `string` provided.\n\n# can match across lines\n\n    Code\n      str_view(\"a\\nb\\nbbb\\nc\", \"(b|\\n)+\")\n    Output\n      \u001b[90m[1] |\u001b[39m a\u001b[36m<\u001b[39m\n          \u001b[90m|\u001b[39m \u001b[36mb\u001b[39m\n          \u001b[90m|\u001b[39m \u001b[36mbbb\u001b[39m\n          \u001b[90m|\u001b[39m \u001b[36m>\u001b[39mc\n\n# str_view_all() is deprecated\n\n    Code\n      str_view_all(\"abc\", \"a|b\")\n    Condition\n      Warning:\n      `str_view_all()` was deprecated in stringr 1.5.0.\n      i Please use `str_view()` instead.\n    Output\n      [1] | <a><b>c\n\n# html mode continues to work\n\n    Code\n      str_view(x, \"[aeiou]\", html = TRUE)$x$html\n    Output\n      <ul>\n        <li><pre><span class='match'>a</span>bc</pre></li>\n        <li><pre>d<span class='match'>e</span>f</pre></li>\n      </ul>\n    Code\n      str_view(x, \"d|e\", html = TRUE)$x$html\n    Output\n      <ul>\n        <li><pre><span class='match'>d</span><span class='match'>e</span>f</pre></li>\n      </ul>\n\n---\n\n    Code\n      str_view(x, html = TRUE, use_escapes = TRUE)$x$html\n    Output\n      <ul>\n        <li><pre> </pre></li>\n        <li><pre>\\u00a0</pre></li>\n        <li><pre>\\n</pre></li>\n      </ul>\n\n"
  },
  {
    "path": "tests/testthat/test-c.R",
    "content": "test_that(\"basic case works\", {\n  test <- c(\"a\", \"b\", \"c\")\n\n  expect_equal(str_c(test), test)\n  expect_equal(str_c(test, sep = \" \"), test)\n  expect_equal(str_c(test, collapse = \"\"), \"abc\")\n})\n\ntest_that(\"obeys tidyverse recycling rules\", {\n  expect_equal(str_c(), character())\n\n  expect_equal(str_c(\"x\", character()), character())\n  expect_equal(str_c(\"x\", NULL), \"x\")\n\n  expect_snapshot(str_c(c(\"x\", \"y\"), character()), error = TRUE)\n  expect_equal(str_c(c(\"x\", \"y\"), NULL), c(\"x\", \"y\"))\n})\n\ntest_that(\"vectorised arguments error\", {\n  expect_snapshot(error = TRUE, {\n    str_c(letters, sep = c(\"a\", \"b\"))\n    str_c(letters, collapse = c(\"a\", \"b\"))\n  })\n})\n"
  },
  {
    "path": "tests/testthat/test-case.R",
    "content": "test_that(\"to_upper and to_lower have equivalent base versions\", {\n  x <- \"This is a sentence.\"\n  expect_identical(str_to_upper(x), toupper(x))\n  expect_identical(str_to_lower(x), tolower(x))\n})\n\ntest_that(\"to_title creates one capital letter per word\", {\n  x <- \"This is a sentence.\"\n  expect_equal(str_count(x, \"\\\\W+\"), str_count(str_to_title(x), \"[[:upper:]]\"))\n})\n\ntest_that(\"to_sentence capitalizes just the first letter\", {\n  expect_identical(str_to_sentence(\"a Test\"), \"A test\")\n})\n\ntest_that(\"case conversions preserve names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_to_lower(x)), names(x))\n  expect_equal(names(str_to_upper(x)), names(x))\n  expect_equal(names(str_to_title(x)), names(x))\n})\n\n# programming cases -----------------------------------------------------------\n\ntest_that(\"to_camel can control case of first argument\", {\n  expect_equal(str_to_camel(\"my_variable\"), \"myVariable\")\n  expect_equal(str_to_camel(\"my$variable\"), \"myVariable\")\n  expect_equal(str_to_camel(\" my    variable  \"), \"myVariable\")\n  expect_equal(str_to_camel(\"my_variable\", first_upper = TRUE), \"MyVariable\")\n})\n\ntest_that(\"to_kebab converts to kebab case\", {\n  expect_equal(str_to_kebab(\"myVariable\"), \"my-variable\")\n  expect_equal(str_to_kebab(\"MyVariable\"), \"my-variable\")\n  expect_equal(str_to_kebab(\"1MyVariable1\"), \"1-my-variable-1\")\n  expect_equal(str_to_kebab(\"My$Variable\"), \"my-variable\")\n  expect_equal(str_to_kebab(\" My   Variable  \"), \"my-variable\")\n  expect_equal(str_to_kebab(\"testABCTest\"), \"test-abc-test\")\n  expect_equal(str_to_kebab(\"IlÉtaitUneFois\"), \"il-était-une-fois\")\n})\n\ntest_that(\"to_snake converts to snake case\", {\n  expect_equal(str_to_snake(\"myVariable\"), \"my_variable\")\n  expect_equal(str_to_snake(\"MyVariable\"), \"my_variable\")\n  expect_equal(str_to_snake(\"1MyVariable1\"), \"1_my_variable_1\")\n  expect_equal(str_to_snake(\"My$Variable\"), \"my_variable\")\n  expect_equal(str_to_snake(\" My   Variable  \"), \"my_variable\")\n  expect_equal(str_to_snake(\"testABCTest\"), \"test_abc_test\")\n  expect_equal(str_to_snake(\"IlÉtaitUneFois\"), \"il_était_une_fois\")\n})\n\ntest_that(\"to_words handles common compound cases\", {\n  expect_equal(to_words(\"a_b\"), \"a b\")\n  expect_equal(to_words(\"a-b\"), \"a b\")\n  expect_equal(to_words(\"aB\"), \"a b\")\n  expect_equal(to_words(\"a123b\"), \"a 123 b\")\n  expect_equal(to_words(\"HTML\"), \"html\")\n})\n"
  },
  {
    "path": "tests/testthat/test-conv.R",
    "content": "test_that(\"encoding conversion works\", {\n  skip_on_os(\"windows\")\n\n  x <- rawToChar(as.raw(177))\n  expect_equal(str_conv(x, \"latin1\"), \"±\")\n})\n\ntest_that(\"check encoding argument\", {\n  expect_snapshot(str_conv(\"A\", c(\"ISO-8859-1\", \"ISO-8859-2\")), error = TRUE)\n})\n\ntest_that(\"str_conv() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_conv(x, \"UTF-8\")), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-count.R",
    "content": "test_that(\"counts are as expected\", {\n  fruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n  expect_equal(str_count(fruit, \"a\"), c(1, 3, 1, 1))\n  expect_equal(str_count(fruit, \"p\"), c(2, 0, 1, 3))\n  expect_equal(str_count(fruit, \"e\"), c(1, 0, 1, 2))\n  expect_equal(str_count(fruit, c(\"a\", \"b\", \"p\", \"n\")), c(1, 1, 1, 1))\n})\n\ntest_that(\"uses tidyverse recycling rules\", {\n  expect_error(str_count(1:2, 1:3), class = \"vctrs_error_incompatible_size\")\n})\n\ntest_that(\"can use fixed() and coll()\", {\n  expect_equal(str_count(\"x.\", fixed(\".\")), 1)\n  expect_equal(str_count(\"\\u0131\", turkish_I()), 1)\n})\n\ntest_that(\"can count boundaries\", {\n  # str_count(x, boundary()) == lengths(str_split(x, boundary()))\n  expect_equal(str_count(\"a b c\", \"\"), 5)\n  expect_equal(str_count(\"a b c\", boundary(\"word\")), 3)\n})\n\ntest_that(\"str_count() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_count(x, \".\")), names(x))\n})\n\ntest_that(\"str_count() drops names when pattern is vector and string is scalar\", {\n  x1 <- c(A = \"ab\")\n  p2 <- c(\"a\", \"b\")\n  expect_null(names(str_count(x1, p2)))\n})\n\ntest_that(\"str_count() preserves names when pattern and string have same length\", {\n  x2 <- c(A = \"ab\", B = \"cd\")\n  p2 <- c(\"a\", \"c\")\n  expect_equal(names(str_count(x2, p2)), names(x2))\n})\n"
  },
  {
    "path": "tests/testthat/test-detect.R",
    "content": "test_that(\"special cases are correct\", {\n  expect_equal(str_detect(NA, \"x\"), NA)\n  expect_equal(str_detect(character(), \"x\"), logical())\n})\n\ntest_that(\"vectorised patterns work\", {\n  expect_equal(str_detect(\"ab\", c(\"a\", \"b\", \"c\")), c(T, T, F))\n  expect_equal(str_detect(c(\"ca\", \"ab\"), c(\"a\", \"c\")), c(T, F))\n\n  # negation works\n  expect_equal(str_detect(\"ab\", c(\"a\", \"b\", \"c\"), negate = TRUE), c(F, F, T))\n})\n\ntest_that(\"str_starts() and str_ends() match expected strings\", {\n  expect_equal(str_starts(c(\"ab\", \"ba\"), \"a\"), c(TRUE, FALSE))\n  expect_equal(str_ends(c(\"ab\", \"ba\"), \"a\"), c(FALSE, TRUE))\n\n  # negation\n  expect_equal(str_starts(c(\"ab\", \"ba\"), \"a\", negate = TRUE), c(FALSE, TRUE))\n  expect_equal(str_ends(c(\"ab\", \"ba\"), \"a\", negate = TRUE), c(TRUE, FALSE))\n\n  # correct precedence\n  expect_equal(str_starts(c(\"ab\", \"ba\", \"cb\"), \"a|b\"), c(TRUE, TRUE, FALSE))\n  expect_equal(str_ends(c(\"ab\", \"ba\", \"bc\"), \"a|b\"), c(TRUE, TRUE, FALSE))\n})\n\ntest_that(\"can use fixed() and coll()\", {\n  expect_equal(str_detect(\"X\", fixed(\".\")), FALSE)\n  expect_equal(str_starts(\"X\", fixed(\".\")), FALSE)\n  expect_equal(str_ends(\"X\", fixed(\".\")), FALSE)\n\n  expect_equal(str_detect(\"\\u0131\", turkish_I()), TRUE)\n  expect_equal(str_starts(\"\\u0131\", turkish_I()), TRUE)\n  expect_equal(str_ends(\"\\u0131\", turkish_I()), TRUE)\n})\n\ntest_that(\"can't empty/boundary\", {\n  expect_snapshot(error = TRUE, {\n    str_detect(\"x\", \"\")\n    str_starts(\"x\", \"\")\n    str_ends(\"x\", \"\")\n  })\n})\n\ntest_that(\"functions use tidyverse recycling rules\", {\n  expect_snapshot(error = TRUE, {\n    str_detect(1:2, 1:3)\n    str_starts(1:2, 1:3)\n    str_ends(1:2, 1:3)\n    str_like(1:2, c(\"a\", \"b\", \"c\"))\n  })\n})\n\ntest_that(\"detection functions preserve names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_detect(x, \"[123]\")), names(x))\n  expect_equal(names(str_starts(x, \"1\")), names(x))\n  expect_equal(names(str_ends(x, \"1\")), names(x))\n  expect_equal(names(str_like(x, \"%\")), names(x))\n  expect_equal(names(str_ilike(x, \"%\")), names(x))\n})\n\ntest_that(\"detection drops names when pattern is vector and string is scalar\", {\n  x1 <- c(A = \"ab\")\n  p2 <- c(\"a\", \"b\")\n  expect_null(names(str_detect(x1, p2)))\n  expect_null(names(str_starts(x1, p2)))\n  expect_null(names(str_ends(x1, p2)))\n  expect_null(names(str_like(x1, p2)))\n  expect_null(names(str_ilike(x1, p2)))\n})\n\ntest_that(\"detection preserves names when pattern and string have same length\", {\n  x2 <- c(A = \"ab\", B = \"cd\")\n  p2 <- c(\"a\", \"c\")\n  expect_equal(names(str_detect(x2, p2)), names(x2))\n  expect_equal(names(str_starts(x2, p2)), names(x2))\n  expect_equal(names(str_ends(x2, p2)), names(x2))\n  expect_equal(names(str_like(x2, p2)), names(x2))\n  expect_equal(names(str_ilike(x2, p2)), names(x2))\n})\n\n# str_like ----------------------------------------------------------------\n\ntest_that(\"str_like is case sensitive\", {\n  expect_true(str_like(\"abc\", \"ab%\"))\n  expect_false(str_like(\"abc\", \"AB%\"))\n  expect_snapshot(str_like(\"abc\", regex(\"x\")), error = TRUE)\n})\n\ntest_that(\"ignore_case is deprecated but still respected\", {\n  expect_snapshot(out <- str_like(\"abc\", \"AB%\", ignore_case = TRUE))\n  expect_equal(out, TRUE)\n\n  expect_warning(out <- str_like(\"abc\", \"AB%\", ignore_case = FALSE))\n  expect_equal(out, FALSE)\n})\n\ntest_that(\"str_ilike works\", {\n  expect_true(str_ilike(\"abc\", \"ab%\"))\n  expect_true(str_ilike(\"abc\", \"AB%\"))\n  expect_snapshot(str_ilike(\"abc\", regex(\"x\")), error = TRUE)\n})\n\ntest_that(\"like_to_regex generates expected regexps\", {\n  expect_equal(like_to_regex(\"ab%\"), \"^ab.*$\")\n  expect_equal(like_to_regex(\"ab_\"), \"^ab.$\")\n\n  # escaping\n  expect_equal(like_to_regex(\"ab\\\\%\"), \"^ab\\\\%$\")\n  expect_equal(like_to_regex(\"ab[%]\"), \"^ab[%]$\")\n})\n"
  },
  {
    "path": "tests/testthat/test-dup.R",
    "content": "test_that(\"basic duplication works\", {\n  expect_equal(str_dup(\"a\", 3), \"aaa\")\n  expect_equal(str_dup(\"abc\", 2), \"abcabc\")\n  expect_equal(str_dup(c(\"a\", \"b\"), 2), c(\"aa\", \"bb\"))\n  expect_equal(str_dup(c(\"a\", \"b\"), c(2, 3)), c(\"aa\", \"bbb\"))\n})\n\ntest_that(\"0 duplicates equals empty string\", {\n  expect_equal(str_dup(\"a\", 0), \"\")\n  expect_equal(str_dup(c(\"a\", \"b\"), 0), rep(\"\", 2))\n})\n\ntest_that(\"uses tidyverse recycling rules\", {\n  expect_error(str_dup(1:2, 1:3), class = \"vctrs_error_incompatible_size\")\n})\n\ntest_that(\"uses sep argument\", {\n  expect_equal(str_dup(\"abc\", 1, sep = \"-\"), \"abc\")\n  expect_equal(str_dup(\"abc\", 2, sep = \"-\"), \"abc-abc\")\n\n  expect_equal(str_dup(c(\"a\", \"b\"), 2, sep = \"-\"), c(\"a-a\", \"b-b\"))\n  expect_equal(str_dup(c(\"a\", \"b\"), c(1, 2), sep = \"-\"), c(\"a\", \"b-b\"))\n\n  expect_equal(str_dup(character(), 1, sep = \"-\"), character())\n  expect_equal(str_dup(character(), 2, sep = \"-\"), character())\n})\n\ntest_that(\"separator must be a single string\", {\n  expect_snapshot(error = TRUE, {\n    str_dup(\"a\", 3, sep = 1)\n    str_dup(\"a\", 3, sep = c(\"-\", \";\"))\n  })\n})\n\ntest_that(\"str_dup() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_dup(x, 2)), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-equal.R",
    "content": "test_that(\"vectorised using TRR\", {\n  expect_equal(str_equal(\"a\", character()), logical())\n  expect_equal(str_equal(\"a\", \"b\"), FALSE)\n  expect_equal(str_equal(\"a\", c(\"a\", \"b\")), c(TRUE, FALSE))\n  expect_snapshot(str_equal(letters[1:3], c(\"a\", \"b\")), error = TRUE)\n})\n\ntest_that(\"can ignore case\", {\n  expect_equal(str_equal(\"a\", \"A\"), FALSE)\n  expect_equal(str_equal(\"a\", \"A\", ignore_case = TRUE), TRUE)\n})\n"
  },
  {
    "path": "tests/testthat/test-escape.R",
    "content": "test_that(\"multiplication works\", {\n  expect_equal(\n    str_escape(\".^$|*+?{}[]()\"),\n    \"\\\\.\\\\^\\\\$\\\\|\\\\*\\\\+\\\\?\\\\{\\\\}\\\\[\\\\]\\\\(\\\\)\"\n  )\n  expect_equal(str_escape(\"\\\\\"), \"\\\\\\\\\")\n})\n\ntest_that(\"str_escape() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_escape(x)), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-extract.R",
    "content": "test_that(\"single pattern extracted correctly\", {\n  test <- c(\"one two three\", \"a b c\")\n\n  expect_equal(\n    str_extract_all(test, \"[a-z]+\"),\n    list(c(\"one\", \"two\", \"three\"), c(\"a\", \"b\", \"c\"))\n  )\n\n  expect_equal(\n    str_extract_all(test, \"[a-z]{3,}\"),\n    list(c(\"one\", \"two\", \"three\"), character())\n  )\n})\n\ntest_that(\"uses tidyverse recycling rules\", {\n  expect_error(\n    str_extract(c(\"a\", \"b\"), c(\"a\", \"b\", \"c\")),\n    class = \"vctrs_error_incompatible_size\"\n  )\n  expect_error(\n    str_extract_all(c(\"a\", \"b\"), c(\"a\", \"b\", \"c\")),\n    class = \"vctrs_error_incompatible_size\"\n  )\n})\n\n\ntest_that(\"no match yields empty vector\", {\n  expect_equal(str_extract_all(\"a\", \"b\")[[1]], character())\n})\n\ntest_that(\"str_extract extracts first match if found, NA otherwise\", {\n  shopping_list <- c(\"apples x4\", \"bag of flour\", \"bag of sugar\", \"milk x2\")\n  word_1_to_4 <- str_extract(shopping_list, \"\\\\b[a-z]{1,4}\\\\b\")\n\n  expect_length(word_1_to_4, length(shopping_list))\n  expect_equal(word_1_to_4[1], NA_character_)\n})\n\ntest_that(\"can extract a group\", {\n  expect_equal(str_extract(\"abc\", \"(.).(.)\", group = 1), \"a\")\n  expect_equal(str_extract(\"abc\", \"(.).(.)\", group = 2), \"c\")\n})\n\ntest_that(\"can use fixed() and coll()\", {\n  expect_equal(str_extract(\"x.x\", fixed(\".\")), \".\")\n  expect_equal(str_extract_all(\"x.x.\", fixed(\".\")), list(c(\".\", \".\")))\n\n  expect_equal(str_extract(\"\\u0131\", turkish_I()), \"\\u0131\")\n  expect_equal(str_extract_all(\"\\u0131I\", turkish_I()), list(c(\"\\u0131\", \"I\")))\n})\n\ntest_that(\"can extract boundaries\", {\n  expect_equal(str_extract(\"a b c\", \"\"), \"a\")\n  expect_equal(\n    str_extract_all(\"a b c\", \"\"),\n    list(c(\"a\", \" \", \"b\", \" \", \"c\"))\n  )\n\n  expect_equal(str_extract(\"a b c\", boundary(\"word\")), \"a\")\n  expect_equal(\n    str_extract_all(\"a b c\", boundary(\"word\")),\n    list(c(\"a\", \"b\", \"c\"))\n  )\n})\n\ntest_that(\"str_extract() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_extract(x, \"[0-9]\")), names(x))\n})\n\ntest_that(\"str_extract_all() preserves names on outer structure\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_extract_all(x, \"[0-9]\")), names(x))\n})\n\ntest_that(\"str_extract and extract_all handle vectorised patterns and names\", {\n  x1 <- c(A = \"ab\")\n  p2 <- c(\"a\", \"b\")\n  expect_null(names(str_extract(x1, p2)))\n  expect_null(names(str_extract_all(x1, p2)))\n\n  x2 <- c(A = \"ab\", B = \"cd\")\n  expect_equal(names(str_extract(x2, p2)), names(x2))\n  expect_equal(names(str_extract_all(x2, p2)), names(x2))\n})\n"
  },
  {
    "path": "tests/testthat/test-flatten.R",
    "content": "test_that(\"equivalent to paste with collapse\", {\n  expect_equal(str_flatten(letters), paste0(letters, collapse = \"\"))\n})\n\ntest_that(\"collapse must be single string\", {\n  expect_snapshot(str_flatten(\"A\", c(\"a\", \"b\")), error = TRUE)\n})\n\ntest_that(\"last optionally used instead of final separator\", {\n  expect_equal(str_flatten(letters[1:3], \", \", \", and \"), \"a, b, and c\")\n  expect_equal(str_flatten(letters[1:2], \", \", \", and \"), \"a, and b\")\n  expect_equal(str_flatten(letters[1], \", \", \", and \"), \"a\")\n})\n\ntest_that(\"can remove missing values\", {\n  expect_equal(str_flatten(c(\"a\", NA)), NA_character_)\n  expect_equal(str_flatten(c(\"a\", NA), na.rm = TRUE), \"a\")\n})\n\ntest_that(\"str_flatten_oxford removes comma iif necessary\", {\n  expect_equal(str_flatten_comma(letters[1:2], \", or \"), \"a or b\")\n\n  expect_equal(str_flatten_comma(letters[1:3], \", or \"), \"a, b, or c\")\n  expect_equal(str_flatten_comma(letters[1:3], \" or \"), \"a, b or c\")\n  expect_equal(str_flatten_comma(letters[1:3]), \"a, b, c\")\n})\n"
  },
  {
    "path": "tests/testthat/test-glue.R",
    "content": "test_that(\"verify wrapper is functional\", {\n  expect_equal(as.character(str_glue(\"a {b}\", b = \"b\")), \"a b\")\n\n  df <- data.frame(b = \"b\")\n  expect_equal(as.character(str_glue_data(df, \"a {b}\", b = \"b\")), \"a b\")\n})\n\ntest_that(\"verify trim is functional\", {\n  expect_equal(as.character(str_glue(\"L1\\t \\n  \\tL2\")), \"L1\\t \\nL2\")\n\n  expect_equal(\n    as.character(str_glue(\"L1\\t \\n  \\tL2\", .trim = FALSE)),\n    \"L1\\t \\n  \\tL2\"\n  )\n})\n"
  },
  {
    "path": "tests/testthat/test-interp.R",
    "content": "test_that(\"str_interp works with default env\", {\n  subject <- \"statistics\"\n  number <- 7\n  floating <- 6.656\n\n  expect_equal(\n    str_interp(\"A ${subject}. B $[d]{number}. C $[.2f]{floating}.\"),\n    \"A statistics. B 7. C 6.66.\"\n  )\n\n  expect_equal(\n    str_interp(\"Pi is approximately $[.5f]{pi}\"),\n    \"Pi is approximately 3.14159\"\n  )\n})\n\ntest_that(\"str_interp works with lists and data frames.\", {\n  expect_equal(\n    str_interp(\n      \"One value, ${value1}, and then another, ${value2*2}.\",\n      list(value1 = 10, value2 = 20)\n    ),\n    \"One value, 10, and then another, 40.\"\n  )\n\n  expect_equal(\n    str_interp(\n      \"Values are $[.2f]{max(Sepal.Width)} and $[.2f]{min(Sepal.Width)}.\",\n      iris\n    ),\n    \"Values are 4.40 and 2.00.\"\n  )\n})\n\ntest_that(\"str_interp works with nested expressions\", {\n  amount <- 1337\n\n  expect_equal(\n    str_interp(\"Works with } nested { braces too: $[.2f]{{{2 + 2}*{amount}}}\"),\n    \"Works with } nested { braces too: 5348.00\"\n  )\n})\n\ntest_that(\"str_interp works in the absense of placeholders\", {\n  expect_equal(\n    str_interp(\"A quite static string here.\"),\n    \"A quite static string here.\"\n  )\n})\n\ntest_that(\"str_interp fails when encountering nested placeholders\", {\n  msg <- \"This will never see the light of day\"\n  num <- 1.2345\n\n  expect_snapshot(error = TRUE, {\n    str_interp(\"${${msg}}\")\n    str_interp(\"$[.2f]{${msg}}\")\n  })\n})\n\ntest_that(\"str_interp fails when input is not a character string\", {\n  expect_snapshot(str_interp(3L), error = TRUE)\n})\n\ntest_that(\"str_interp wraps parsing errors\", {\n  expect_snapshot(str_interp(\"This is a ${1 +}\"), error = TRUE)\n})\n\ntest_that(\"str_interp formats list independetly of other placeholders\", {\n  a_list <- c(\"item1\", \"item2\", \"item3\")\n  other <- \"1\"\n  extract <- function(text) regmatches(text, regexpr(\"xx[^x]+xx\", text))\n  from_list <- extract(str_interp(\"list: xx${a_list}xx\"))\n  from_both <- extract(str_interp(\"list: xx${a_list}xx, and another ${other}\"))\n  expect_equal(from_list, from_both)\n})\n"
  },
  {
    "path": "tests/testthat/test-length.R",
    "content": "test_that(\"str_length is number of characters\", {\n  expect_equal(str_length(\"a\"), 1)\n  expect_equal(str_length(\"ab\"), 2)\n  expect_equal(str_length(\"abc\"), 3)\n})\n\ntest_that(\"str_length of missing string is missing\", {\n  expect_equal(str_length(NA), NA_integer_)\n  expect_equal(str_length(c(NA, 1)), c(NA, 1))\n  expect_equal(str_length(\"NA\"), 2)\n})\n\ntest_that(\"str_length of factor is length of level\", {\n  expect_equal(str_length(factor(\"a\")), 1)\n  expect_equal(str_length(factor(\"ab\")), 2)\n  expect_equal(str_length(factor(\"abc\")), 3)\n})\n\ntest_that(\"str_width returns display width\", {\n  x <- c(\"\\u0308\", \"x\", \"\\U0001f60a\")\n  expect_equal(str_width(x), c(0, 1, 2))\n})\n\ntest_that(\"length/width preserve names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_length(x)), names(x))\n  expect_equal(names(str_width(x)), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-locate.R",
    "content": "test_that(\"basic location matching works\", {\n  expect_equal(str_locate(\"abc\", \"a\")[1, ], c(start = 1, end = 1))\n  expect_equal(str_locate(\"abc\", \"b\")[1, ], c(start = 2, end = 2))\n  expect_equal(str_locate(\"abc\", \"c\")[1, ], c(start = 3, end = 3))\n  expect_equal(str_locate(\"abc\", \".+\")[1, ], c(start = 1, end = 3))\n})\n\ntest_that(\"uses tidyverse recycling rules\", {\n  expect_error(str_locate(1:2, 1:3), class = \"vctrs_error_incompatible_size\")\n  expect_error(\n    str_locate_all(1:2, 1:3),\n    class = \"vctrs_error_incompatible_size\"\n  )\n})\n\ntest_that(\"locations are integers\", {\n  strings <- c(\"a b c\", \"d e f\")\n  expect_true(is.integer(str_locate(strings, \"[a-z]\")))\n\n  res <- str_locate_all(strings, \"[a-z]\")[[1]]\n  expect_true(is.integer(res))\n  expect_true(is.integer(invert_match(res)))\n})\n\ntest_that(\"both string and patterns are vectorised\", {\n  strings <- c(\"abc\", \"def\")\n\n  locs <- str_locate(strings, \"a\")\n  expect_equal(locs[, \"start\"], c(1, NA))\n\n  locs <- str_locate(strings, c(\"a\", \"d\"))\n  expect_equal(locs[, \"start\"], c(1, 1))\n  expect_equal(locs[, \"end\"], c(1, 1))\n\n  locs <- str_locate_all(c(\"abab\"), c(\"a\", \"b\"))\n  expect_equal(locs[[1]][, \"start\"], c(1, 3))\n  expect_equal(locs[[2]][, \"start\"], c(2, 4))\n})\n\ntest_that(\"can use fixed() and coll()\", {\n  expect_equal(str_locate(\"x.x\", fixed(\".\")), cbind(start = 2, end = 2))\n  expect_equal(\n    str_locate_all(\"x.x.\", fixed(\".\")),\n    list(cbind(start = c(2, 4), end = c(2, 4)))\n  )\n\n  expect_equal(str_locate(\"\\u0131\", turkish_I()), cbind(start = 1, end = 1))\n  expect_equal(\n    str_locate_all(\"\\u0131I\", turkish_I()),\n    list(cbind(start = 1:2, end = 1:2))\n  )\n})\n\ntest_that(\"can use boundaries\", {\n  expect_equal(\n    str_locate(\" x  y\", \"\"),\n    cbind(start = 1, end = 1)\n  )\n  expect_equal(\n    str_locate_all(\"abc\", \"\"),\n    list(cbind(start = 1:3, end = 1:3))\n  )\n\n  expect_equal(\n    str_locate(\" xy\", boundary(\"word\")),\n    cbind(start = 2, end = 3)\n  )\n  expect_equal(\n    str_locate_all(\" ab  cd\", boundary(\"word\")),\n    list(cbind(start = c(2, 6), end = c(3, 7)))\n  )\n})\n\ntest_that(\"str_locate() preserves row names when 1:1 with input\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(rownames(str_locate(x, \"[0-9]\")), names(x))\n})\n\ntest_that(\"str_locate_all() preserves names on outer structure\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_locate_all(x, \"[0-9]\")), names(x))\n})\n\ntest_that(\"locate handles vectorised patterns and names\", {\n  x1 <- c(A = \"ab\")\n  p2 <- c(\"a\", \"b\")\n  expect_null(rownames(str_locate(x1, p2)))\n  expect_null(names(str_locate_all(x1, p2)))\n\n  x2 <- c(A = \"ab\", B = \"cd\")\n  expect_equal(rownames(str_locate(x2, p2)), names(x2))\n  expect_equal(names(str_locate_all(x2, p2)), names(x2))\n})\n"
  },
  {
    "path": "tests/testthat/test-match.R",
    "content": "set.seed(1410)\nnum <- matrix(sample(9, 10 * 10, replace = T), ncol = 10)\nnum_flat <- apply(num, 1, str_c, collapse = \"\")\n\nphones <- str_c(\n  \"(\",\n  num[, 1],\n  num[, 2],\n  num[, 3],\n  \") \",\n  num[, 4],\n  num[, 5],\n  num[, 6],\n  \" \",\n  num[, 7],\n  num[, 8],\n  num[, 9],\n  num[, 10]\n)\n\ntest_that(\"empty strings return correct matrix of correct size\", {\n  skip_if_not_installed(\"stringi\", \"1.2.2\")\n\n  expect_equal(str_match(NA, \"(a)\"), matrix(NA_character_, 1, 2))\n  expect_equal(str_match(character(), \"(a)\"), matrix(character(), 0, 2))\n})\n\ntest_that(\"no matching cases returns 1 column matrix\", {\n  res <- str_match(c(\"a\", \"b\"), \".\")\n\n  expect_equal(nrow(res), 2)\n  expect_equal(ncol(res), 1)\n\n  expect_equal(res[, 1], c(\"a\", \"b\"))\n})\n\ntest_that(\"single match works when all match\", {\n  matches <- str_match(phones, \"\\\\(([0-9]{3})\\\\) ([0-9]{3}) ([0-9]{4})\")\n\n  expect_equal(nrow(matches), length(phones))\n  expect_equal(ncol(matches), 4)\n\n  expect_equal(matches[, 1], phones)\n\n  matches_flat <- apply(matches[, -1], 1, str_c, collapse = \"\")\n  expect_equal(matches_flat, num_flat)\n})\n\ntest_that(\"match returns NA when some inputs don't match\", {\n  matches <- str_match(\n    c(phones, \"blah\", NA),\n    \"\\\\(([0-9]{3})\\\\) ([0-9]{3}) ([0-9]{4})\"\n  )\n\n  expect_equal(nrow(matches), length(phones) + 2)\n  expect_equal(ncol(matches), 4)\n\n  expect_equal(matches[11, ], rep(NA_character_, 4))\n  expect_equal(matches[12, ], rep(NA_character_, 4))\n})\n\ntest_that(\"match returns NA when optional group doesn't match\", {\n  expect_equal(str_match(c(\"ab\", \"a\"), \"(a)(b)?\")[, 3], c(\"b\", NA))\n})\n\ntest_that(\"match_all returns NA when option group doesn't match\", {\n  expect_equal(str_match_all(\"a\", \"(a)(b)?\")[[1]][1, ], c(\"a\", \"a\", NA))\n})\n\ntest_that(\"multiple match works\", {\n  phones_one <- str_c(phones, collapse = \" \")\n  multi_match <- str_match_all(\n    phones_one,\n    \"\\\\(([0-9]{3})\\\\) ([0-9]{3}) ([0-9]{4})\"\n  )\n  single_matches <- str_match(phones, \"\\\\(([0-9]{3})\\\\) ([0-9]{3}) ([0-9]{4})\")\n\n  expect_equal(multi_match[[1]], single_matches)\n})\n\ntest_that(\"match and match_all fail when pattern is not a regex\", {\n  expect_snapshot(error = TRUE, {\n    str_match(phones, fixed(\"3\"))\n    str_match_all(phones, coll(\"9\"))\n  })\n})\n\ntest_that(\"uses tidyverse recycling rules\", {\n  expect_error(\n    str_match(c(\"a\", \"b\"), c(\"a\", \"b\", \"c\")),\n    class = \"vctrs_error_incompatible_size\"\n  )\n  expect_error(\n    str_match_all(c(\"a\", \"b\"), c(\"a\", \"b\", \"c\")),\n    class = \"vctrs_error_incompatible_size\"\n  )\n})\n\ntest_that(\"match can't use other modifiers\", {\n  expect_snapshot(error = TRUE, {\n    str_match(\"x\", coll(\"y\"))\n    str_match_all(\"x\", coll(\"y\"))\n  })\n})\n\ntest_that(\"str_match() preserves row names when 1:1 with input\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(rownames(str_match(x, \"([0-9])\")), names(x))\n})\n\ntest_that(\"str_match_all() preserves names on outer structure\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_match_all(x, \"([0-9])\")), names(x))\n})\n\ntest_that(\"match handles vectorised patterns and names\", {\n  x1 <- c(A = \"ab\")\n  p2 <- c(\"a\", \"b\")\n  expect_null(rownames(str_match(x1, p2)))\n  expect_null(names(str_match_all(x1, p2)))\n\n  x2 <- c(A = \"ab\", B = \"cd\")\n  expect_equal(rownames(str_match(x2, p2)), names(x2))\n  expect_equal(names(str_match_all(x2, p2)), names(x2))\n})\n"
  },
  {
    "path": "tests/testthat/test-modifiers.R",
    "content": "test_that(\"patterns coerced to character\", {\n  x <- factor(\"a\")\n\n  expect_snapshot({\n    . <- regex(x)\n    . <- coll(x)\n    . <- fixed(x)\n  })\n})\n\ntest_that(\"useful error message for bad type\", {\n  expect_snapshot(error = TRUE, {\n    type(1:3)\n  })\n})\n\ntest_that(\"fallback for regex (#433)\", {\n  expect_equal(type(structure(\"x\", class = \"regex\")), \"regex\")\n})\n\ntest_that(\"ignore_case sets strength, but can override manually\", {\n  x1 <- coll(\"x\", strength = 1)\n  x2 <- coll(\"x\", ignore_case = TRUE)\n  x3 <- coll(\"x\")\n\n  expect_equal(attr(x1, \"options\")$strength, 1)\n  expect_equal(attr(x2, \"options\")$strength, 2)\n  expect_equal(attr(x3, \"options\")$strength, 3)\n})\n\ntest_that(\"boundary has length 1\", {\n  expect_length(boundary(), 1)\n})\n\ntest_that(\"subsetting preserves class and options\", {\n  x <- regex(\"a\", multiline = TRUE)\n  expect_equal(x[], x)\n})\n\ntest_that(\"useful errors for NAs\", {\n  expect_snapshot(error = TRUE, {\n    type(NA)\n    type(c(\"a\", \"b\", NA_character_, \"c\"))\n  })\n})\n\ntest_that(\"stringr_pattern methods\", {\n  ex <- coll(c(\"foo\", \"bar\"))\n  expect_true(inherits(ex[1], \"stringr_pattern\"))\n  expect_true(inherits(ex[[1]], \"stringr_pattern\"))\n})\n"
  },
  {
    "path": "tests/testthat/test-pad.R",
    "content": "test_that(\"long strings are unchanged\", {\n  lengths <- sample(40:100, 10)\n  strings <- vapply(\n    lengths,\n    function(x) {\n      str_c(letters[sample(26, x, replace = T)], collapse = \"\")\n    },\n    character(1)\n  )\n\n  padded <- str_pad(strings, width = 30)\n  expect_equal(str_length(padded), str_length(strings))\n})\n\ntest_that(\"directions work for simple case\", {\n  pad <- function(direction) str_pad(\"had\", direction, width = 10)\n\n  expect_equal(pad(\"right\"), \"had       \")\n  expect_equal(pad(\"left\"), \"       had\")\n  expect_equal(pad(\"both\"), \"   had    \")\n})\n\ntest_that(\"padding based of length works\", {\n  # \\u4e2d is a 2-characters-wide Chinese character\n  pad <- function(...) str_pad(\"\\u4e2d\", ..., side = \"both\")\n\n  expect_equal(pad(width = 6), \"  \\u4e2d  \")\n  expect_equal(pad(width = 5, use_width = FALSE), \"  \\u4e2d  \")\n})\n\ntest_that(\"uses tidyverse recycling rules\", {\n  expect_error(\n    str_pad(c(\"a\", \"b\"), 1:3),\n    class = \"vctrs_error_incompatible_size\"\n  )\n  expect_error(\n    str_pad(c(\"a\", \"b\"), 10, pad = c(\"a\", \"b\", \"c\")),\n    class = \"vctrs_error_incompatible_size\"\n  )\n})\n\ntest_that(\"str_pad() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_pad(x, 2, side = \"left\")), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-remove.R",
    "content": "test_that(\"succesfully wraps str_replace_all\", {\n  expect_equal(str_remove_all(\"abababa\", \"ba\"), \"a\")\n  expect_equal(str_remove(\"abababa\", \"ba\"), \"ababa\")\n})\n\ntest_that(\"str_remove() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_remove(x, \"[0-9]\")), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-replace.R",
    "content": "test_that(\"basic replacement works\", {\n  expect_equal(str_replace_all(\"abababa\", \"ba\", \"BA\"), \"aBABABA\")\n  expect_equal(str_replace(\"abababa\", \"ba\", \"BA\"), \"aBAbaba\")\n})\n\ntest_that(\"can replace multiple matches\", {\n  x <- c(\"a1\", \"b2\")\n  y <- str_replace_all(x, c(\"a\" = \"1\", \"b\" = \"2\"))\n  expect_equal(y, c(\"11\", \"22\"))\n})\n\ntest_that(\"even when lengths differ\", {\n  x <- c(\"a1\", \"b2\", \"c3\")\n  y <- str_replace_all(x, c(\"a\" = \"1\", \"b\" = \"2\"))\n  expect_equal(y, c(\"11\", \"22\", \"c3\"))\n})\n\ntest_that(\"multiple matches respects class\", {\n  x <- c(\"x\", \"y\")\n  y <- str_replace_all(x, regex(c(\"X\" = \"a\"), ignore_case = TRUE))\n  expect_equal(y, c(\"a\", \"y\"))\n})\n\ntest_that(\"replacement must be a string\", {\n  expect_snapshot(str_replace(\"x\", \"x\", 1), error = TRUE)\n})\n\ntest_that(\"replacement must be a string\", {\n  expect_equal(str_replace(\"xyz\", \"x\", NA_character_), NA_character_)\n})\n\ntest_that(\"can replace all types of NA values\", {\n  expect_equal(str_replace_na(NA), \"NA\")\n  expect_equal(str_replace_na(NA_character_), \"NA\")\n  expect_equal(str_replace_na(NA_complex_), \"NA\")\n  expect_equal(str_replace_na(NA_integer_), \"NA\")\n  expect_equal(str_replace_na(NA_real_), \"NA\")\n})\n\ntest_that(\"can use fixed() and coll()\", {\n  expect_equal(str_replace(\"x.x\", fixed(\".\"), \"Y\"), \"xYx\")\n  expect_equal(str_replace_all(\"x.x.\", fixed(\".\"), \"Y\"), \"xYxY\")\n\n  expect_equal(str_replace(\"\\u0131\", turkish_I(), \"Y\"), \"Y\")\n  expect_equal(str_replace_all(\"\\u0131I\", turkish_I(), \"Y\"), \"YY\")\n})\n\ntest_that(\"can't replace empty/boundary\", {\n  expect_snapshot(error = TRUE, {\n    str_replace(\"x\", \"\", \"\")\n    str_replace(\"x\", boundary(\"word\"), \"\")\n    str_replace_all(\"x\", \"\", \"\")\n    str_replace_all(\"x\", boundary(\"word\"), \"\")\n  })\n})\n\n# functions ---------------------------------------------------------------\n\ntest_that(\"can replace multiple values\", {\n  expect_equal(str_replace(\"abc\", \"a|c\", toupper), \"Abc\")\n  expect_equal(str_replace_all(\"abc\", \"a|c\", toupper), \"AbC\")\n})\n\ntest_that(\"can use formula\", {\n  expect_equal(str_replace(\"abc\", \"b\", ~\"x\"), \"axc\")\n  expect_equal(str_replace_all(\"abc\", \"b\", ~\"x\"), \"axc\")\n})\n\ntest_that(\"replacement can be different length\", {\n  double <- function(x) str_dup(x, 2)\n  expect_equal(str_replace_all(\"abc\", \"a|c\", double), \"aabcc\")\n})\n\ntest_that(\"replacement is vectorised\", {\n  x <- c(\"\", \"a\", \"b\", \"ab\", \"abc\", \"cba\")\n  expect_equal(\n    str_replace_all(x, \"a|c\", ~ toupper(str_dup(.x, 2))),\n    c(\"\", \"AA\", \"b\", \"AAb\", \"AAbCC\", \"CCbAA\")\n  )\n})\n\ntest_that(\"is forgiving of 0 matches with paste\", {\n  x <- c(\"a\", \"b\", \"c\")\n  expect_equal(str_replace_all(x, \"d\", ~ paste(\"x\", .x)), x)\n})\n\ntest_that(\"useful error if not vectorised correctly\", {\n  x <- c(\"a\", \"b\", \"c\")\n  expect_snapshot(\n    str_replace_all(x, \"a|c\", ~ if (length(x) > 1) stop(\"Bad\")),\n    error = TRUE\n  )\n})\n\ntest_that(\"works with no match\", {\n  expect_equal(str_replace(\"abc\", \"z\", toupper), \"abc\")\n})\n\ntest_that(\"works with zero length match\", {\n  expect_equal(str_replace(\"abc\", \"$\", toupper), \"abc\")\n  expect_equal(str_replace_all(\"abc\", \"$|^\", ~ rep(\"X\", length(.x))), \"XabcX\")\n})\n\ntest_that(\"replacement function must return correct type/length\", {\n  expect_snapshot(error = TRUE, {\n    str_replace_all(\"x\", \"x\", ~1)\n    str_replace_all(\"x\", \"x\", ~ c(\"a\", \"b\"))\n  })\n})\n\n# fix_replacement ---------------------------------------------------------\n\ntest_that(\"backrefs are correctly translated\", {\n  expect_equal(str_replace_all(\"abcde\", \"(b)(c)(d)\", \"\\\\1\"), \"abe\")\n  expect_equal(str_replace_all(\"abcde\", \"(b)(c)(d)\", \"\\\\2\"), \"ace\")\n  expect_equal(str_replace_all(\"abcde\", \"(b)(c)(d)\", \"\\\\3\"), \"ade\")\n\n  # gsub(\"(b)(c)(d)\", \"\\\\0\", \"abcde\", perl=TRUE) gives a0e,\n  # in ICU regex $0 refers to the whole pattern match\n  expect_equal(str_replace_all(\"abcde\", \"(b)(c)(d)\", \"\\\\0\"), \"abcde\")\n\n  # gsub(\"(b)(c)(d)\", \"\\\\4\", \"abcde\", perl=TRUE) is legal,\n  # in ICU regex this gives an U_INDEX_OUTOFBOUNDS_ERROR\n  expect_snapshot(str_replace_all(\"abcde\", \"(b)(c)(d)\", \"\\\\4\"), error = TRUE)\n\n  expect_equal(str_replace_all(\"abcde\", \"bcd\", \"\\\\\\\\1\"), \"a\\\\1e\")\n\n  expect_equal(str_replace_all(\"a!1!2!b\", \"!\", \"$\"), \"a$1$2$b\")\n  expect_equal(str_replace(\"aba\", \"b\", \"$\"), \"a$a\")\n  expect_equal(str_replace(\"aba\", \"b\", \"$$$\"), \"a$$$a\")\n  expect_equal(str_replace(\"aba\", \"(b)\", \"\\\\1$\\\\1$\\\\1\"), \"ab$b$ba\")\n  expect_equal(str_replace(\"aba\", \"(b)\", \"\\\\1$\\\\\\\\1$\\\\1\"), \"ab$\\\\1$ba\")\n  expect_equal(str_replace(\"aba\", \"(b)\", \"\\\\\\\\1$\\\\1$\\\\\\\\1\"), \"a\\\\1$b$\\\\1a\")\n})\n\ntest_that(\"$ are escaped\", {\n  expect_equal(fix_replacement(\"$\"), \"\\\\$\")\n  expect_equal(fix_replacement(\"\\\\$\"), \"\\\\\\\\$\")\n})\n\ntest_that(\"\\1 converted to $1 etc\", {\n  expect_equal(fix_replacement(\"\\\\1\"), \"$1\")\n  expect_equal(fix_replacement(\"\\\\9\"), \"$9\")\n})\n\ntest_that(\"\\\\1 left as is\", {\n  expect_equal(fix_replacement(\"\\\\\\\\1\"), \"\\\\\\\\1\")\n})\n\ntest_that(\"replace functions preserve names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_replace(x, \"[0-9]\", \"x\")), names(x))\n  expect_equal(names(str_replace_all(x, \"[0-9]\", \"x\")), names(x))\n})\n\ntest_that(\"replace functions handle vectorised patterns and names\", {\n  x1 <- c(A = \"ab\")\n  p2 <- c(\"a\", \"b\")\n  expect_null(names(str_replace(x1, p2, \"x\")))\n  expect_null(names(str_replace_all(x1, p2, \"x\")))\n\n  x2 <- c(A = \"ab\", B = \"cd\")\n  expect_equal(names(str_replace(x2, p2, \"x\")), names(x2))\n  expect_equal(names(str_replace_all(x2, p2, \"x\")), names(x2))\n})\n\ntest_that(\"str_replace_na() preserves names\", {\n  y <- c(A = NA, B = \"x\")\n  expect_equal(names(str_replace_na(y)), names(y))\n})\n"
  },
  {
    "path": "tests/testthat/test-sort.R",
    "content": "test_that(\"digits can be sorted/ordered as strings or numbers\", {\n  x <- c(\"2\", \"1\", \"10\")\n\n  expect_equal(str_sort(x, numeric = FALSE), c(\"1\", \"10\", \"2\"))\n  expect_equal(str_sort(x, numeric = TRUE), c(\"1\", \"2\", \"10\"))\n\n  expect_equal(str_order(x, numeric = FALSE), c(2, 3, 1))\n  expect_equal(str_order(x, numeric = TRUE), c(2, 1, 3))\n\n  expect_equal(str_rank(x, numeric = FALSE), c(3, 1, 2))\n  expect_equal(str_rank(x, numeric = TRUE), c(2, 1, 3))\n})\n\ntest_that(\"NA can be at beginning or end\", {\n  x <- c(\"2\", \"1\", NA, \"10\")\n\n  na_end <- str_sort(x, numeric = TRUE, na_last = TRUE)\n  expect_equal(tail(na_end, 1), NA_character_)\n\n  na_start <- str_sort(x, numeric = TRUE, na_last = FALSE)\n  expect_equal(head(na_start, 1), NA_character_)\n})\n\ntest_that(\"str_sort() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  out <- str_sort(x)\n  expect_equal(names(out), c(\"A\", \"B\", \"C\"))\n})\n"
  },
  {
    "path": "tests/testthat/test-split.R",
    "content": "test_that(\"special cases are correct\", {\n  expect_equal(str_split(NA, \"\")[[1]], NA_character_)\n  expect_equal(str_split(character(), \"\"), list())\n})\n\ntest_that(\"str_split functions as expected\", {\n  expect_equal(\n    str_split(c(\"bab\", \"cac\", \"dadad\"), \"a\"),\n    list(c(\"b\", \"b\"), c(\"c\", \"c\"), c(\"d\", \"d\", \"d\"))\n  )\n})\n\ntest_that(\"str_split() can split by special patterns\", {\n  expect_equal(str_split(\"ab\", \"\"), list(c(\"a\", \"b\")))\n  expect_equal(\n    str_split(\"this that.\", boundary(\"word\")),\n    list(c(\"this\", \"that\"))\n  )\n  expect_equal(str_split(\"a-b\", fixed(\"-\")), list(c(\"a\", \"b\")))\n  expect_equal(\n    str_split(\"aXb\", coll(\"X\", ignore_case = TRUE)),\n    list(c(\"a\", \"b\"))\n  )\n})\n\ntest_that(\"boundary() can be recycled\", {\n  expect_equal(str_split(c(\"x\", \"y\"), boundary()), list(\"x\", \"y\"))\n})\n\ntest_that(\"str_split() can control maximum number of splits\", {\n  expect_equal(\n    str_split(c(\"a\", \"a-b\"), n = 1, \"-\"),\n    list(\"a\", \"a-b\")\n  )\n  expect_equal(\n    str_split(c(\"a\", \"a-b\"), n = 3, \"-\"),\n    list(\"a\", c(\"a\", \"b\"))\n  )\n})\n\ntest_that(\"str_split() checks its inputs\", {\n  expect_snapshot(error = TRUE, {\n    str_split(letters[1:3], letters[1:2])\n    str_split(\"x\", 1)\n    str_split(\"x\", \"x\", n = 0)\n  })\n})\n\ntest_that(\"str_split_1 takes string and returns character vector\", {\n  expect_equal(str_split_1(\"abc\", \"\"), c(\"a\", \"b\", \"c\"))\n  expect_snapshot_error(str_split_1(letters, \"\"))\n})\n\ntest_that(\"str_split_fixed pads with empty string\", {\n  expect_equal(\n    str_split_fixed(c(\"a\", \"a-b\"), \"-\", 1),\n    cbind(c(\"a\", \"a-b\"))\n  )\n  expect_equal(\n    str_split_fixed(c(\"a\", \"a-b\"), \"-\", 2),\n    cbind(c(\"a\", \"a\"), c(\"\", \"b\"))\n  )\n  expect_equal(\n    str_split_fixed(c(\"a\", \"a-b\"), \"-\", 3),\n    cbind(c(\"a\", \"a\"), c(\"\", \"b\"), c(\"\", \"\"))\n  )\n})\n\ntest_that(\"str_split_fixed check its inputs\", {\n  expect_snapshot(str_split_fixed(\"x\", \"x\", 0), error = TRUE)\n})\n\n# str_split_i -------------------------------------------------------------\n\ntest_that(\"str_split_i can extract from LHS or RHS\", {\n  expect_equal(str_split_i(c(\"1-2-3\", \"4-5\"), \"-\", 1), c(\"1\", \"4\"))\n  expect_equal(str_split_i(c(\"1-2-3\", \"4-5\"), \"-\", -1), c(\"3\", \"5\"))\n})\n\ntest_that(\"str_split_i returns NA for absent components\", {\n  expect_equal(str_split_i(c(\"a\", \"b-c\"), \"-\", 2), c(NA, \"c\"))\n  expect_equal(str_split_i(c(\"a\", \"b-c\"), \"-\", 3), c(NA_character_, NA))\n\n  expect_equal(str_split_i(c(\"1-2-3\", \"4-5\"), \"-\", -3), c(\"1\", NA))\n  expect_equal(str_split_i(c(\"1-2-3\", \"4-5\"), \"-\", -4), c(NA_character_, NA))\n})\n\ntest_that(\"str_split_i check its inputs\", {\n  expect_snapshot(error = TRUE, {\n    str_split_i(\"x\", \"x\", 0)\n    str_split_i(\"x\", \"x\", 0.5)\n  })\n})\n\ntest_that(\"split functions preserve names on outer structures\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_split(x, \"\")), names(x))\n  expect_equal(rownames(str_split(x, \"\", simplify = TRUE)), names(x))\n  expect_equal(rownames(str_split_fixed(x, \"\", 1)), names(x))\n})\n\ntest_that(\"str_split_i() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_split_i(x, \" \", 1)), names(x))\n})\n\ntest_that(\"split handles vectorised patterns and names\", {\n  x1 <- c(A = \"ab\")\n  p2 <- c(\"a\", \"b\")\n  expect_null(names(str_split(x1, p2)))\n  expect_null(rownames(str_split(x1, p2, simplify = TRUE)))\n  expect_null(rownames(str_split_fixed(x1, p2, 1)))\n\n  x2 <- c(A = \"ab\", B = \"cd\")\n  expect_equal(names(str_split(x2, p2)), names(x2))\n  expect_equal(rownames(str_split(x2, p2, simplify = TRUE)), names(x2))\n  expect_equal(rownames(str_split_fixed(x2, p2, 1)), names(x2))\n})\n"
  },
  {
    "path": "tests/testthat/test-sub.R",
    "content": "test_that(\"correct substring extracted\", {\n  alphabet <- str_c(letters, collapse = \"\")\n  expect_equal(str_sub(alphabet, 1, 3), \"abc\")\n  expect_equal(str_sub(alphabet, 24, 26), \"xyz\")\n})\n\ntest_that(\"can extract multiple substrings\", {\n  expect_equal(\n    str_sub_all(c(\"abc\", \"def\"), list(c(1, 2), 1), list(c(1, 2), 2)),\n    list(c(\"a\", \"b\"), \"de\")\n  )\n})\n\ntest_that(\"arguments expanded to longest\", {\n  alphabet <- str_c(letters, collapse = \"\")\n\n  expect_equal(\n    str_sub(alphabet, c(1, 24), c(3, 26)),\n    c(\"abc\", \"xyz\")\n  )\n\n  expect_equal(\n    str_sub(c(\"abc\", \"xyz\"), 2, 2),\n    c(\"b\", \"y\")\n  )\n})\n\ntest_that(\"can supply start and end/length as a matrix\", {\n  x <- c(\"abc\", \"def\")\n  expect_equal(str_sub(x, cbind(1, end = 1)), c(\"a\", \"d\"))\n  expect_equal(str_sub(x, cbind(1, length = 2)), c(\"ab\", \"de\"))\n\n  expect_equal(\n    str_sub_all(x, cbind(c(1, 2), end = c(2, 3))),\n    list(c(\"ab\", \"bc\"), c(\"de\", \"ef\"))\n  )\n\n  str_sub(x, cbind(1, end = 1)) <- c(\"A\", \"D\")\n  expect_equal(x, c(\"Abc\", \"Def\"))\n})\n\ntest_that(\"specifying only end subsets from start\", {\n  alphabet <- str_c(letters, collapse = \"\")\n  expect_equal(str_sub(alphabet, end = 3), \"abc\")\n})\n\ntest_that(\"specifying only start subsets to end\", {\n  alphabet <- str_c(letters, collapse = \"\")\n  expect_equal(str_sub(alphabet, 24), \"xyz\")\n})\n\ntest_that(\"specifying -1 as end selects entire string\", {\n  expect_equal(\n    str_sub(\"ABCDEF\", c(4, 5), c(5, -1)),\n    c(\"DE\", \"EF\")\n  )\n\n  expect_equal(\n    str_sub(\"ABCDEF\", c(4, 5), c(-1, -1)),\n    c(\"DEF\", \"EF\")\n  )\n})\n\ntest_that(\"negative values select from end\", {\n  expect_equal(str_sub(\"ABCDEF\", 1, -4), \"ABC\")\n  expect_equal(str_sub(\"ABCDEF\", -3), \"DEF\")\n})\n\ntest_that(\"missing arguments give missing results\", {\n  expect_equal(str_sub(NA), NA_character_)\n  expect_equal(str_sub(NA, 1, 3), NA_character_)\n  expect_equal(str_sub(c(NA, \"NA\"), 1, 3), c(NA, \"NA\"))\n\n  expect_equal(str_sub(\"test\", NA, NA), NA_character_)\n  expect_equal(str_sub(c(NA, \"test\"), NA, NA), rep(NA_character_, 2))\n})\n\ntest_that(\"negative length or out of range gives empty string\", {\n  expect_equal(str_sub(\"abc\", 2, 1), \"\")\n  expect_equal(str_sub(\"abc\", 4, 5), \"\")\n})\n\ntest_that(\"replacement works\", {\n  x <- \"BBCDEF\"\n  str_sub(x, 1, 1) <- \"A\"\n  expect_equal(x, \"ABCDEF\")\n\n  str_sub(x, -1, -1) <- \"K\"\n  expect_equal(x, \"ABCDEK\")\n\n  str_sub(x, -2, -1) <- \"EFGH\"\n  expect_equal(x, \"ABCDEFGH\")\n\n  str_sub(x, 2, -2) <- \"\"\n  expect_equal(x, \"AH\")\n})\n\ntest_that(\"replacement with NA works\", {\n  x <- \"BBCDEF\"\n  str_sub(x, NA) <- \"A\"\n  expect_equal(x, NA_character_)\n\n  x <- \"BBCDEF\"\n  str_sub(x, NA, omit_na = TRUE) <- \"A\"\n  str_sub(x, 1, 1, omit_na = TRUE) <- NA\n  expect_equal(x, \"BBCDEF\")\n})\n\ntest_that(\"bad vectorisation gives informative error\", {\n  x <- \"a\"\n  expect_snapshot(error = TRUE, {\n    str_sub(x, 1:2, 1:3)\n    str_sub(x, 1:2, 1:2) <- 1:3\n  })\n})\n\ntest_that(\"str_sub() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_sub(x, 1, 1)), names(x))\n})\n\ntest_that(\"str_sub_all() preserves names on outer structure\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_sub_all(x, 1, 1)), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-subset.R",
    "content": "test_that(\"can subset with regexps\", {\n  x <- c(\"a\", \"b\", \"c\")\n  expect_equal(str_subset(x, \"a|c\"), c(\"a\", \"c\"))\n  expect_equal(str_subset(x, \"a|c\", negate = TRUE), \"b\")\n})\n\ntest_that(\"can subset with fixed patterns\", {\n  expect_equal(str_subset(c(\"i\", \"I\"), fixed(\"i\")), \"i\")\n  expect_equal(\n    str_subset(c(\"i\", \"I\"), fixed(\"i\", ignore_case = TRUE)),\n    c(\"i\", \"I\")\n  )\n\n  # negation works\n  expect_equal(str_subset(c(\"i\", \"I\"), fixed(\"i\"), negate = TRUE), \"I\")\n})\n\ntest_that(\"str_which is equivalent to grep\", {\n  expect_equal(\n    str_which(head(letters), \"[aeiou]\"),\n    grep(\"[aeiou]\", head(letters))\n  )\n\n  # negation works\n  expect_equal(\n    str_which(head(letters), \"[aeiou]\", negate = TRUE),\n    grep(\"[aeiou]\", head(letters), invert = TRUE)\n  )\n})\n\ntest_that(\"can use fixed() and coll()\", {\n  expect_equal(str_subset(c(\"x\", \".\"), fixed(\".\")), \".\")\n  expect_equal(str_subset(c(\"i\", \"\\u0131\"), turkish_I()), \"\\u0131\")\n})\n\ntest_that(\"can't use boundaries\", {\n  expect_snapshot(error = TRUE, {\n    str_subset(c(\"a\", \"b c\"), \"\")\n    str_subset(c(\"a\", \"b c\"), boundary())\n  })\n})\n\ntest_that(\"keep names\", {\n  fruit <- c(A = \"apple\", B = \"banana\", C = \"pear\", D = \"pineapple\")\n  expect_identical(names(str_subset(fruit, \"b\")), \"B\")\n  expect_identical(names(str_subset(fruit, \"p\")), c(\"A\", \"C\", \"D\"))\n  expect_identical(names(str_subset(fruit, \"x\")), as.character())\n})\n\ntest_that(\"str_subset() preserves names of retained elements\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  out <- str_subset(x, \"[12]\")\n  expect_equal(names(out), c(\"B\", \"A\"))\n})\n\ntest_that(\"str_subset() never matches missing values\", {\n  expect_equal(str_subset(c(\"a\", NA, \"b\"), \".\"), c(\"a\", \"b\"))\n  expect_identical(str_subset(NA_character_, \".\"), character(0))\n})\n"
  },
  {
    "path": "tests/testthat/test-trim.R",
    "content": "test_that(\"trimming removes spaces\", {\n  expect_equal(str_trim(\"abc   \"), \"abc\")\n  expect_equal(str_trim(\"   abc\"), \"abc\")\n  expect_equal(str_trim(\"  abc   \"), \"abc\")\n})\n\ntest_that(\"trimming removes tabs\", {\n  expect_equal(str_trim(\"abc\\t\"), \"abc\")\n  expect_equal(str_trim(\"\\tabc\"), \"abc\")\n  expect_equal(str_trim(\"\\tabc\\t\"), \"abc\")\n})\n\ntest_that(\"side argument restricts trimming\", {\n  expect_equal(str_trim(\" abc \", \"left\"), \"abc \")\n  expect_equal(str_trim(\" abc \", \"right\"), \" abc\")\n})\n\ntest_that(\"str_squish removes excess spaces from all parts of string\", {\n  expect_equal(str_squish(\"ab\\t\\tc\\t\"), \"ab c\")\n  expect_equal(str_squish(\"\\ta  bc\"), \"a bc\")\n  expect_equal(str_squish(\"\\ta\\t bc\\t\"), \"a bc\")\n})\n\ntest_that(\"trimming functions preserve names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_trim(x)), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-trunc.R",
    "content": "test_that(\"NA values in input pass through unchanged\", {\n  expect_equal(\n    str_trunc(NA_character_, width = 5),\n    NA_character_\n  )\n  expect_equal(\n    str_trunc(c(\"foobar\", NA), 5),\n    c(\"fo...\", NA)\n  )\n})\n\ntest_that(\"truncations work for all elements of a vector\", {\n  expect_equal(\n    str_trunc(c(\"abcd\", \"abcde\", \"abcdef\"), width = 5),\n    c(\"abcd\", \"abcde\", \"ab...\")\n  )\n})\n\ntest_that(\"truncations work for all sides\", {\n  trunc <- function(direction, width) {\n    str_trunc(\n      \"This string is moderately long\",\n      direction,\n      width = width\n    )\n  }\n\n  expect_equal(trunc(\"right\", 20), \"This string is mo...\")\n  expect_equal(trunc(\"left\", 20), \"...s moderately long\")\n  expect_equal(trunc(\"center\", 20), \"This stri...ely long\")\n\n  expect_equal(trunc(\"right\", 3), \"...\")\n  expect_equal(trunc(\"left\", 3), \"...\")\n  expect_equal(trunc(\"center\", 3), \"...\")\n\n  expect_equal(trunc(\"right\", 4), \"T...\")\n  expect_equal(trunc(\"left\", 4), \"...g\")\n  expect_equal(trunc(\"center\", 4), \"T...\")\n\n  expect_equal(trunc(\"right\", 5), \"Th...\")\n  expect_equal(trunc(\"left\", 5), \"...ng\")\n  expect_equal(trunc(\"center\", 5), \"T...g\")\n})\n\ntest_that(\"does not truncate to a length shorter than elipsis\", {\n  expect_snapshot(error = TRUE, {\n    str_trunc(\"foobar\", 2)\n    str_trunc(\"foobar\", 3, ellipsis = \"....\")\n  })\n})\n\ntest_that(\"str_trunc correctly snips rhs-of-ellipsis for truncated strings\", {\n  trunc <- function(width, side) {\n    str_trunc(\n      c(\"\", \"a\", \"aa\", \"aaa\", \"aaaa\", \"aaaaaaa\"),\n      width,\n      side,\n      ellipsis = \"..\"\n    )\n  }\n\n  expect_equal(trunc(4, \"right\"), c(\"\", \"a\", \"aa\", \"aaa\", \"aaaa\", \"aa..\"))\n  expect_equal(trunc(4, \"left\"), c(\"\", \"a\", \"aa\", \"aaa\", \"aaaa\", \"..aa\"))\n  expect_equal(trunc(4, \"center\"), c(\"\", \"a\", \"aa\", \"aaa\", \"aaaa\", \"a..a\"))\n\n  expect_equal(trunc(3, \"right\"), c(\"\", \"a\", \"aa\", \"aaa\", \"a..\", \"a..\"))\n  expect_equal(trunc(3, \"left\"), c(\"\", \"a\", \"aa\", \"aaa\", \"..a\", \"..a\"))\n  expect_equal(trunc(3, \"center\"), c(\"\", \"a\", \"aa\", \"aaa\", \"a..\", \"a..\"))\n\n  expect_equal(trunc(2, \"right\"), c(\"\", \"a\", \"aa\", \"..\", \"..\", \"..\"))\n  expect_equal(trunc(2, \"left\"), c(\"\", \"a\", \"aa\", \"..\", \"..\", \"..\"))\n  expect_equal(trunc(2, \"center\"), c(\"\", \"a\", \"aa\", \"..\", \"..\", \"..\"))\n})\n\ntest_that(\"str_trunc() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_trunc(x, 3)), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-unique.R",
    "content": "test_that(\"unique values returned for strings with duplicate values\", {\n  expect_equal(str_unique(c(\"a\", \"a\", \"a\")), \"a\")\n  expect_equal(str_unique(c(NA_character_, NA_character_)), NA_character_)\n})\n\ntest_that(\"can ignore case\", {\n  expect_equal(str_unique(c(\"a\", \"A\"), ignore_case = TRUE), \"a\")\n})\n\ntest_that(\"str_unique() preserves names of first occurrences\", {\n  y <- c(A = \"a\", A2 = \"a\", B = \"b\")\n  out <- str_unique(y)\n  expect_equal(names(out), c(\"A\", \"B\"))\n})\n"
  },
  {
    "path": "tests/testthat/test-utils.R",
    "content": "test_that(\"keep_names() returns logical flag based on inputs\", {\n  expect_true(keep_names(\"a\", \"x\"))\n  expect_false(keep_names(\"a\", c(\"x\", \"y\")))\n  expect_true(keep_names(c(\"a\", \"b\"), \"x\"))\n  expect_true(keep_names(c(\"a\", \"b\"), c(\"x\", \"y\")))\n})\n\ntest_that(\"copy_names() applies names to vectors if present\", {\n  expect_equal(\n    copy_names(c(A = \"a\", B = \"b\"), c(\"x\", \"y\")),\n    c(A = \"x\", B = \"y\")\n  )\n\n  expect_equal(\n    copy_names(c(\"a\", \"b\"), c(\"x\", \"y\")),\n    c(\"x\", \"y\")\n  )\n})\n\ntest_that(\"copy_names() applies rownames to matrices if present\", {\n  from <- c(A = \"a\", B = \"b\")\n  to <- matrix(c(\"x\", \"y\"), nrow = 2)\n\n  expected <- to\n  rownames(expected) <- names(from)\n\n  expect_equal(copy_names(from, to), expected)\n  expect_equal(copy_names(c(\"a\", \"b\"), to), to)\n})\n"
  },
  {
    "path": "tests/testthat/test-view.R",
    "content": "test_that(\"results are truncated\", {\n  expect_snapshot(str_view(words))\n\n  # and can control with option\n  local_options(stringr.view_n = 5)\n  expect_snapshot(str_view(words))\n})\n\ntest_that(\"indices come from original vector\", {\n  expect_snapshot(str_view(letters, \"a|z\", match = TRUE))\n})\n\ntest_that(\"view highlights all matches\", {\n  x <- c(\"abc\", \"def\", \"fgh\")\n\n  expect_snapshot({\n    str_view(x, \"[aeiou]\")\n    str_view(x, \"d|e\")\n  })\n})\n\ntest_that(\"view highlights whitespace (except a space/nl)\", {\n  x <- c(\" \", \"\\u00A0\", \"\\n\", \"\\t\")\n  expect_snapshot({\n    str_view(x)\n\n    \"or can instead use escapes\"\n    str_view(x, use_escapes = TRUE)\n  })\n})\n\ntest_that(\"view displays message for empty vectors\", {\n  expect_snapshot(str_view(character()))\n})\n\ntest_that(\"match argument controls what is shown\", {\n  x <- c(\"abc\", \"def\", \"fgh\", NA)\n  out <- str_view(x, \"d|e\", match = NA)\n  expect_length(out, 4)\n\n  out <- str_view(x, \"d|e\", match = TRUE)\n  expect_length(out, 1)\n\n  out <- str_view(x, \"d|e\", match = FALSE)\n  expect_length(out, 3)\n})\n\ntest_that(\"can match across lines\", {\n  local_reproducible_output(crayon = TRUE)\n  expect_snapshot(str_view(\"a\\nb\\nbbb\\nc\", \"(b|\\n)+\"))\n})\n\ntest_that(\"vectorised over pattern\", {\n  x <- str_view(\"a\", c(\"a\", \"b\"), match = NA)\n  expect_equal(length(x), 2)\n})\n\ntest_that(\"[ preserves class\", {\n  x <- str_view(letters)\n  expect_s3_class(x[], \"stringr_view\")\n})\n\ntest_that(\"str_view_all() is deprecated\", {\n  expect_snapshot(str_view_all(\"abc\", \"a|b\"))\n})\n\ntest_that(\"html mode continues to work\", {\n  skip_if_not_installed(\"htmltools\")\n  skip_if_not_installed(\"htmlwidgets\")\n\n  x <- c(\"abc\", \"def\", \"fgh\")\n  expect_snapshot({\n    str_view(x, \"[aeiou]\", html = TRUE)$x$html\n    str_view(x, \"d|e\", html = TRUE)$x$html\n  })\n\n  # can use escapes\n  x <- c(\" \", \"\\u00A0\", \"\\n\")\n  expect_snapshot({\n    str_view(x, html = TRUE, use_escapes = TRUE)$x$html\n  })\n})\n"
  },
  {
    "path": "tests/testthat/test-word.R",
    "content": "test_that(\"word extraction\", {\n  expect_equal(\"walk\", word(\"walk the moon\"))\n  expect_equal(\"walk\", word(\"walk the moon\", 1))\n  expect_equal(\"moon\", word(\"walk the moon\", 3))\n  expect_equal(\"the moon\", word(\"walk the moon\", 2, 3))\n})\n\ntest_that(\"words past end return NA\", {\n  expect_equal(word(\"a b c\", 4), NA_character_)\n})\n\ntest_that(\"negative parameters\", {\n  expect_equal(\"moon\", word(\"walk the moon\", -1, -1))\n  expect_equal(\"walk the moon\", word(\"walk the moon\", -3, -1))\n  expect_equal(\"walk the moon\", word(\"walk the moon\", -5, -1))\n})\n\ntest_that(\"word() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(word(x, 1)), names(x))\n})\n"
  },
  {
    "path": "tests/testthat/test-wrap.R",
    "content": "test_that(\"wrapping removes spaces\", {\n  expect_equal(str_wrap(\"\"), \"\")\n  expect_equal(str_wrap(\" \"), \"\")\n  expect_equal(str_wrap(\"  a  \"), \"a\")\n})\n\ntest_that(\"wrapping with width of 0 puts each word on own line\", {\n  n_returns <- letters %>%\n    str_c(collapse = \" \") %>%\n    str_wrap(0) %>%\n    str_count(\"\\n\")\n  expect_equal(n_returns, length(letters) - 1)\n})\n\ntest_that(\"wrapping at whitespace break works\", {\n  expect_equal(str_wrap(\"a/b\", width = 0, whitespace_only = TRUE), \"a/b\")\n  expect_equal(str_wrap(\"a/b\", width = 0, whitespace_only = FALSE), \"a/\\nb\")\n})\n\ntest_that(\"str_wrap() preserves names\", {\n  x <- c(C = \"3\", B = \"2\", A = \"1\")\n  expect_equal(names(str_wrap(x)), names(x))\n})\n"
  },
  {
    "path": "tests/testthat.R",
    "content": "library(testthat)\nlibrary(stringr)\n\ntest_check(\"stringr\")\n"
  },
  {
    "path": "vignettes/.gitignore",
    "content": "/.quarto/\n"
  },
  {
    "path": "vignettes/from-base.Rmd",
    "content": "---\ntitle: \"From base R\"\nauthor: \"Sara Stoudt\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{From base R}\n  %\\VignetteEngine{knitr::rmarkdown}\n  %\\VignetteEncoding{UTF-8}\n---\n\n```{r}\n#| label: setup\n#| include: false\n\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#>\"\n)\n\nlibrary(stringr)\nlibrary(magrittr)\n```\n\nThis vignette compares stringr functions to their base R equivalents to help users transitioning from using base R to stringr. \n\n# Overall differences\n\nWe'll begin with a lookup table between the most important stringr functions and their base R equivalents.\n\n```{r}\n#| label: stringr-base-r-diff\n#| echo: false\n\ndata_stringr_base_diff <- tibble::tribble(\n  ~stringr,                                        ~base_r,\n  \"str_detect(string, pattern)\",                   \"grepl(pattern, x)\",\n  \"str_dup(string, times)\",                        \"strrep(x, times)\",\n  \"str_extract(string, pattern)\",                  \"regmatches(x, m = regexpr(pattern, text))\",\n  \"str_extract_all(string, pattern)\",              \"regmatches(x, m = gregexpr(pattern, text))\",\n  \"str_length(string)\",                            \"nchar(x)\",\n  \"str_locate(string, pattern)\",                   \"regexpr(pattern, text)\",\n  \"str_locate_all(string, pattern)\",               \"gregexpr(pattern, text)\",\n  \"str_match(string, pattern)\",                    \"regmatches(x, m = regexec(pattern, text))\",\n  \"str_order(string)\",                             \"order(...)\",\n  \"str_replace(string, pattern, replacement)\",     \"sub(pattern, replacement, x)\",\n  \"str_replace_all(string, pattern, replacement)\", \"gsub(pattern, replacement, x)\",\n  \"str_sort(string)\",                              \"sort(x)\",\n  \"str_split(string, pattern)\",                    \"strsplit(x, split)\",\n  \"str_sub(string, start, end)\",                   \"substr(x, start, stop)\",\n  \"str_subset(string, pattern)\",                   \"grep(pattern, x, value = TRUE)\",\n  \"str_to_lower(string)\",                          \"tolower(x)\",\n  \"str_to_title(string)\",                          \"tools::toTitleCase(text)\",\n  \"str_to_upper(string)\",                          \"toupper(x)\",\n  \"str_trim(string)\",                              \"trimws(x)\",\n  \"str_which(string, pattern)\",                    \"grep(pattern, x)\",\n  \"str_wrap(string)\",                              \"strwrap(x)\"\n)\n\n# create MD table, arranged alphabetically by stringr fn name\ndata_stringr_base_diff %>%\n  dplyr::mutate(dplyr::across(\n      .cols = everything(),\n      .fns = ~ paste0(\"`\", .x, \"`\"))\n  ) %>%\n  dplyr::arrange(stringr) %>%\n  dplyr::rename(`base R` = base_r) %>%\n  gt::gt() %>%\n  gt::fmt_markdown(columns = everything()) %>%\n  gt::tab_options(column_labels.font.weight = \"bold\")\n```\n\nOverall the main differences between base R and stringr are:\n\n1.  stringr functions start with `str_` prefix; base R string functions have no\n    consistent naming scheme.\n   \n1.  The order of inputs is usually different between base R and stringr. \n    In base R, the `pattern` to match usually comes first; in stringr, the\n    `string` to manupulate always comes first. This makes stringr easier \n    to use in pipes, and with `lapply()` or `purrr::map()`.\n    \n1.  Functions in stringr tend to do less, where many of the string processing \n    functions in base R have multiple purposes.\n    \n1.  The output and input of stringr functions has been carefully designed.\n    For example, the output of `str_locate()` can be fed directly into \n    `str_sub()`; the same is not true of `regexpr()` and `substr()`.\n    \n1.  Base functions use arguments (like `perl`, `fixed`, and `ignore.case`)\n    to control how the pattern is interpreted. To avoid dependence between\n    arguments, stringr instead uses helper functions (like `fixed()`, \n    `regex()`, and `coll()`).\n\nNext we'll walk through each of the functions, noting the similarities and important differences. These examples are adapted from the stringr documentation and here they are contrasted with the analogous base R operations.\n\n# Detect matches\n\n## `str_detect()`: Detect the presence or absence of a pattern in a string\n\nSuppose you want to know whether each word in a vector of fruit names contains an \"a\". \n\n```{r}\nfruit <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n\n# base\ngrepl(pattern = \"a\", x = fruit)\n\n# stringr\nstr_detect(fruit, pattern = \"a\")\n```\n\nIn base you would use `grepl()` (see the \"l\" and think logical) while in stringr you use `str_detect()` (see the verb \"detect\" and think of a yes/no action). \n\n## `str_which()`: Find positions matching a pattern\n\nNow you want to identify the positions of the words in a vector of fruit names that contain an \"a\". \n\n```{r}\n# base\ngrep(pattern = \"a\", x = fruit)\n\n# stringr\nstr_which(fruit, pattern = \"a\")\n```\n\nIn base you would use `grep()` while in stringr you use `str_which()` (by analogy to `which()`). \n\n## `str_count()`: Count the number of matches in a string\n\nHow many \"a\"s are in each fruit?\n\n```{r}\n# base \nloc <- gregexpr(pattern = \"a\", text = fruit, fixed = TRUE)\nsapply(loc, function(x) length(attr(x, \"match.length\")))\n\n# stringr\nstr_count(fruit, pattern = \"a\")\n```\n\nThis information can be gleaned from `gregexpr()` in base, but you need to look at the `match.length` attribute as the vector uses a length-1 integer vector (`-1`) to indicate no match.\n\n## `str_locate()`: Locate the position of patterns in a string\n\nWithin each fruit, where does the first \"p\" occur? Where are all of the \"p\"s?\n\n```{r}\nfruit3 <- c(\"papaya\", \"lime\", \"apple\")\n\n# base\nstr(gregexpr(pattern = \"p\", text = fruit3))\n\n# stringr\nstr_locate(fruit3, pattern = \"p\")\nstr_locate_all(fruit3, pattern = \"p\")\n```\n\n# Subset strings\n\n## `str_sub()`: Extract and replace substrings from a character vector\n\nWhat if we want to grab part of a string?\n\n```{r}\nhw <- \"Hadley Wickham\"\n\n# base\nsubstr(hw, start = 1, stop = 6)\nsubstring(hw, first = 1) \n\n# stringr\nstr_sub(hw, start = 1, end = 6)\nstr_sub(hw, start = 1)\nstr_sub(hw, end = 6)\n```\n\nIn base you could use `substr()` or `substring()`. The former requires both a start and stop of the substring while the latter assumes the stop will be the end of the string. The stringr version, `str_sub()` has the same functionality, but also gives a default start value (the beginning of the string). Both the base and stringr functions have the same order of expected inputs. \n\nIn stringr you can use negative numbers to index from the right-hand side string: -1 is the last letter, -2 is the second to last, and so on.\n\n```{r}\nstr_sub(hw, start = 1, end = -1)\nstr_sub(hw, start = -5, end = -2)\n```\n\nBoth base R and stringr subset are vectorized over their parameters. This means you can either choose the same subset across multiple strings or specify different subsets for different strings.\n\n```{r}\nal <- \"Ada Lovelace\"\n\n# base\nsubstr(c(hw,al), start = 1, stop = 6)\nsubstr(c(hw,al), start = c(1,1), stop = c(6,7))\n\n# stringr\nstr_sub(c(hw,al), start = 1, end = -1)\nstr_sub(c(hw,al), start = c(1,1), end = c(-1,-2))\n```\n\nstringr will automatically recycle the first argument to the same length as `start` and `stop`:\n\n```{r}\nstr_sub(hw, start = 1:5)\n```\n\nWhereas the base equivalent silently uses just the first value:\n\n```{r}\nsubstr(hw, start = 1:5, stop = 15)\n```\n\n## `str_sub() <- `: Subset assignment\n\n`substr()` behaves in a surprising way when you replace a substring with a different number of characters:\n\n```{r}\n# base\nx <- \"ABCDEF\"\nsubstr(x, 1, 3) <- \"x\"\nx\n```\n\n`str_sub()` does what you would expect:\n\n```{r}\n# stringr\nx <- \"ABCDEF\"\nstr_sub(x, 1, 3) <- \"x\"\nx\n```\n\n## `str_subset()`: Keep strings matching a pattern, or find positions\n\nWe may want to retrieve strings that contain a pattern of interest:\n\n```{r}\n# base\ngrep(pattern = \"g\", x = fruit, value = TRUE)\n\n# stringr\nstr_subset(fruit, pattern = \"g\")\n```\n\n## `str_extract()`: Extract matching patterns from a string\n\nWe may want to pick out certain patterns from a string, for example, the digits in a shopping list:\n\n```{r}\nshopping_list <- c(\"apples x4\", \"bag of flour\", \"10\", \"milk x2\")\n\n# base\nmatches <- regexpr(pattern = \"\\\\d+\", text = shopping_list) # digits\nregmatches(shopping_list, m = matches)\n\nmatches <- gregexpr(pattern = \"[a-z]+\", text = shopping_list) # words\nregmatches(shopping_list, m = matches)\n\n# stringr\nstr_extract(shopping_list, pattern = \"\\\\d+\") \nstr_extract_all(shopping_list, \"[a-z]+\")\n```\n\nBase R requires the combination of `regexpr()` with `regmatches()`; but note that the strings without matches are dropped from the output. stringr provides `str_extract()` and `str_extract_all()`, and the output is always the same length as the input.\n\n## `str_match()`: Extract matched groups from a string\n\nWe may also want to extract groups from a string. Here I'm going to use the scenario from Section 14.4.3 in [R for Data Science](https://r4ds.had.co.nz/strings.html).\n\n```{r}\nhead(sentences)\nnoun <- \"([A]a|[Tt]he) ([^ ]+)\"\n\n# base\nmatches <- regexec(pattern = noun, text = head(sentences))\ndo.call(\"rbind\", regmatches(x = head(sentences), m = matches))\n\n# stringr\nstr_match(head(sentences), pattern = noun)\n```\n\nAs for extracting the full match base R requires the combination of two functions, and inputs with no matches are dropped from the output.\n\n# Manage lengths\n\n## `str_length()`: The length of a string\n\nTo determine the length of a string, base R uses `nchar()` (not to be confused with `length()` which gives the length of vectors, etc.) while stringr uses `str_length()`.\n\n```{r}\n# base\nnchar(letters)\n\n# stringr\nstr_length(letters)\n```\n\nThere are some subtle differences between base and stringr here. `nchar()` requires a character vector, so it will return an error if used on a factor. `str_length()` can handle a factor input.\n\n```{r}\n#| error: true\n\n# base\nnchar(factor(\"abc\")) \n```\n\n```{r}\n# stringr\nstr_length(factor(\"abc\"))\n```\n\nNote that \"characters\" is a poorly defined concept, and technically both `nchar()` and `str_length()` returns the number of code points. This is usually the same as what you'd consider to be a charcter, but not always:\n\n```{r}\nx <- c(\"\\u00fc\", \"u\\u0308\")\nx\n\nnchar(x)\nstr_length(x)\n```\n\n## `str_pad()`: Pad a string\n\nTo pad a string to a certain width, use stringr's `str_pad()`. In base R you could use `sprintf()`, but unlike `str_pad()`, `sprintf()` has many other functionalities. \n\n```{r}\n# base\nsprintf(\"%30s\", \"hadley\")\nsprintf(\"%-30s\", \"hadley\")\n# \"both\" is not as straightforward\n\n# stringr\nrbind(\n  str_pad(\"hadley\", 30, \"left\"),\n  str_pad(\"hadley\", 30, \"right\"),\n  str_pad(\"hadley\", 30, \"both\")\n)\n```\n\n## `str_trunc()`: Truncate a character string\n\nThe stringr package provides an easy way to truncate a character string: `str_trunc()`. Base R has no function to do this directly.\n\n```{r}\nx <- \"This string is moderately long\"\n\n# stringr\nrbind(\n  str_trunc(x, 20, \"right\"),\n  str_trunc(x, 20, \"left\"),\n  str_trunc(x, 20, \"center\")\n)\n```\n\n## `str_trim()`: Trim whitespace from a string\n\nSimilarly, stringr provides `str_trim()` to trim whitespace from a string. This is analogous to base R's `trimws()` added in R 3.3.0.\n\n```{r}\n# base\ntrimws(\" String with trailing and leading white space\\t\")\ntrimws(\"\\n\\nString with trailing and leading white space\\n\\n\")\n\n# stringr\nstr_trim(\" String with trailing and leading white space\\t\")\nstr_trim(\"\\n\\nString with trailing and leading white space\\n\\n\")\n```\n\nThe stringr function `str_squish()` allows for extra whitespace within a string to be trimmed (in contrast to `str_trim()` which removes whitespace at the beginning and/or end of string). In base R, one might take advantage of `gsub()` to accomplish the same effect.\n\n```{r}\n# stringr\nstr_squish(\" String with trailing, middle,   and leading white space\\t\")\nstr_squish(\"\\n\\nString with excess, trailing and leading white space\\n\\n\")\n```\n\n## `str_wrap()`: Wrap strings into nicely formatted paragraphs\n\n`strwrap()` and `str_wrap()` use different algorithms. `str_wrap()` uses the famous [Knuth-Plass algorithm](http://litherum.blogspot.com/2015/07/knuth-plass-line-breaking-algorithm.html). \n\n```{r}\ngettysburg <- \"Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.\"\n\n# base\ncat(strwrap(gettysburg, width = 60), sep = \"\\n\")\n\n# stringr\ncat(str_wrap(gettysburg, width = 60), \"\\n\")\n```\n\nNote that `strwrap()` returns a character vector with one element for each line; `str_wrap()` returns a single string containing line breaks.\n\n# Mutate strings\n\n## `str_replace()`: Replace matched patterns in a string\n\nTo replace certain patterns within a string, stringr provides the functions `str_replace()` and `str_replace_all()`. The base R equivalents are `sub()` and `gsub()`. Note the difference in default input order again. \n\n```{r}\nfruits <- c(\"apple\", \"banana\", \"pear\", \"pineapple\")\n\n# base\nsub(\"[aeiou]\", \"-\", fruits)\ngsub(\"[aeiou]\", \"-\", fruits)\n\n# stringr\nstr_replace(fruits, \"[aeiou]\", \"-\")\nstr_replace_all(fruits, \"[aeiou]\", \"-\")\n```\n\n## case: Convert case of a string\n\nBoth stringr and base R have functions to convert to upper and lower case.  Title case is also provided in stringr.\n\n```{r}\ndog <- \"The quick brown dog\"\n\n# base\ntoupper(dog)\ntolower(dog)\ntools::toTitleCase(dog)\n\n# stringr\nstr_to_upper(dog)\nstr_to_lower(dog)\nstr_to_title(dog)\n```\n\nIn stringr we can control the locale, while in base R locale distinctions are controlled with global variables. Therefore, the output of your base R code may vary across different computers with different global settings.\n\n```{r}\n# stringr\nstr_to_upper(\"i\") # English\nstr_to_upper(\"i\", locale = \"tr\") # Turkish\n```\n\n# Join and split\n\n## `str_flatten()`: Flatten a string\n\nIf we want to take elements of a string vector and collapse them to a single string we can use the `collapse` argument in `paste()` or use stringr's `str_flatten()`.\n\n```{r}\n# base\npaste0(letters, collapse = \"-\")\n\n# stringr\nstr_flatten(letters, collapse = \"-\")\n```\n\nThe advantage of `str_flatten()` is that it always returns a vector the same length as its input; to predict the return length of `paste()` you must carefully read all arguments.\n\n## `str_dup()`: duplicate strings within a character vector\n\nTo duplicate strings within a character vector use `strrep()` (in R 3.3.0 or greater) or `str_dup()`:\n\n```{r}\n#| eval: !expr getRversion() >= \"3.3.0\"\n\nfruit <- c(\"apple\", \"pear\", \"banana\")\n\n# base\nstrrep(fruit, 2)\nstrrep(fruit, 1:3)\n\n# stringr\nstr_dup(fruit, 2)\nstr_dup(fruit, 1:3)\n```\n\n## `str_split()`: Split up a string into pieces\n\nTo split a string into pieces with breaks based on a particular pattern match stringr uses `str_split()` and base R uses `strsplit()`. Unlike most other functions, `strsplit()` starts with the character vector to modify.\n\n```{r}\nfruits <- c(\n  \"apples and oranges and pears and bananas\",\n  \"pineapples and mangos and guavas\"\n)\n# base\nstrsplit(fruits, \" and \")\n\n# stringr\nstr_split(fruits, \" and \")\n```\n\nThe stringr package's `str_split()` allows for more control over the split, including restricting the number of possible matches.\n\n```{r}\n# stringr\nstr_split(fruits, \" and \", n = 3)\nstr_split(fruits, \" and \", n = 2)\n```\n\n## `str_glue()`: Interpolate strings\n\nIt's often useful to interpolate varying values into a fixed string. In base R, you can use `sprintf()` for this purpose; stringr provides a wrapper for the more general purpose [glue](https://glue.tidyverse.org) package.\n\n```{r}\nname <- \"Fred\"\nage <- 50\nanniversary <- as.Date(\"1991-10-12\")\n\n# base\nsprintf(\n  \"My name is %s my age next year is %s and my anniversary is %s.\", \n  name,\n  age + 1,\n  format(anniversary, \"%A, %B %d, %Y\")\n)\n\n# stringr\nstr_glue(\n  \"My name is {name}, \",\n  \"my age next year is {age + 1}, \",\n  \"and my anniversary is {format(anniversary, '%A, %B %d, %Y')}.\"\n)\n```\n\n# Order strings\n\n## `str_order()`: Order or sort a character vector\n\nBoth base R and stringr have separate functions to order and sort strings.\n\n```{r}\n# base\norder(letters)\nsort(letters)\n\n# stringr\nstr_order(letters)\nstr_sort(letters)\n```\n\nSome options in `str_order()` and `str_sort()` don't have analogous base R options. For example, the stringr functions have a `locale` argument to control how to order or sort. In base R the locale is a global setting, so the outputs of `sort()` and `order()` may differ across different computers. For example, in the Norwegian alphabet, å comes after z:\n\n```{r}\nx <- c(\"å\", \"a\", \"z\")\nstr_sort(x)\nstr_sort(x, locale = \"no\")\n```\n\nThe stringr functions also have a `numeric` argument to sort digits numerically instead of treating them as strings.\n\n```{r}\n# stringr\nx <- c(\"100a10\", \"100a5\", \"2b\", \"2a\")\nstr_sort(x)\nstr_sort(x, numeric = TRUE)\n```\n"
  },
  {
    "path": "vignettes/locale-sensitive.Rmd",
    "content": "---\ntitle: \"Locale sensitive functions\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{Locale sensitive functions}\n  %\\VignetteEngine{knitr::rmarkdown}\n  %\\VignetteEncoding{UTF-8}\n---\n\n```{r}\n#| include: FALSE\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#>\"\n)\nlibrary(stringr)\n```\n\nA locale is a set of parameters that define a user's language, region, and cultural preferences. It determines language-specific rules for text processing, including how to:\n\n- Convert between uppercase and lowercase letters\n- Sort text alphabetically\n- Format dates, numbers, and currency\n- Handle character encoding and display\n\nIn stringr, you can control the locale using the `locale` argument, which takes language codes like \"en\" (English), \"tr\" (Turkish), or \"es_MX\" (Mexican Spanish). In general, a locale is a lower-case language abbreviation, optionally followed by an underscore (_) and an upper-case region identifier. You can see which locales are supported in stringr by running `stringi::stri_locale_list()`.\n\nThis vignette describes locale-sensitive stringr functions, i.e. functions with a `locale` argument. These functions fall into two broad categories:\n\n1. Case conversion\n2. Sorting and ordering\n\n## Case conversion\n\n`str_to_lower()`, `str_to_upper()`, `str_to_title()`, and `str_to_sentence()` all change the case of their inputs. But while most languages that use the Latin alphabet (like English) have upper and lower case, the rules for converting between the two aren't always the same. For example, Turkish has two forms of the letter \"I\": as well as \"i\" and \"I\", Turkish also has \"ı\", the dotless lowercase i, and \"İ\" is the dotted uppercase I. This means the rules for converting i to upper case and I to lower case are different from English:\n\n```{r}\n# English\nstr_to_upper(\"i\")\nstr_to_lower(\"I\")\n\n# Turkish\nstr_to_upper(\"i\", locale = \"tr\")\nstr_to_lower(\"I\", locale = \"tr\")\n```\n\nAnother example is Dutch, where \"ij\" is a digraph treated as a single letter. This means that `str_to_sentence()` will incorrectly capitalize \"ij\" at the start of a sentence unless you use a Dutch locale:\n\n```{r}\n#| warning: false\ndutch_sentence <- \"ijsland is een prachtig land in Noord-Europa.\"\n\n# Incorrect\nstr_to_sentence(dutch_sentence)\n# Correct\nstr_to_sentence(dutch_sentence, locale = \"nl\")\n```\n\nCase conversion also comes up in another situation: case-insensitive comparison. This is relevant in two contexts. First, `str_equal()` and `str_unique()` can optionally ignore case, so it's important to also supply locale when working with non-English text. For example, imagine we're searching for a Turkish name, ignoring case:\n\n```{r}\nturkish_names <- c(\"İpek\", \"Işık\", \"İbrahim\")\nsearch_name <- \"ipek\"\n\n# incorrect\nstr_equal(turkish_names, search_name, ignore_case = TRUE)\n\n# correct\nstr_equal(turkish_names, search_name, ignore_case = TRUE, locale = \"tr\")\n```\n\nCase conversion also comes up in pattern matching functions like `str_detect()`. You might be accustomed to use `ignore_case = TRUE` with `regex()` or `fixed()`, but if you want to use locale-sensitive comparison you instead need to use `coll()`:\n\n```{r}\n# incorrect\nstr_detect(turkish_names, fixed(search_name, ignore_case = TRUE))\n\n# correct\nstr_detect(turkish_names, coll(search_name, ignore_case = TRUE, locale = \"tr\"))\n```\n\n## Sorting and ordering\n\n`str_sort()`, `str_order()`, and `str_rank()` all rely on the alphabetical ordering of letters. But not every language uses the same ordering as English. For example, Lithuanian places 'y' between 'i' and 'k', and Czech treats \"ch\" as a single compound letter that sorts after all other words beginning with 'h'. This means that to correctly sort words in these languages, you must provide the appropriate locale:\n\n```{r}\nczech_words <- c(\"had\", \"chata\", \"hrad\", \"chůze\")\nlithuanian_words <- c(\"ąžuolas\", \"ėglė\", \"šuo\", \"yra\", \"žuvis\")\n\n# incorrect\nstr_sort(czech_words)\nstr_sort(lithuanian_words)\n\n# correct\nstr_sort(czech_words, locale = \"cs\")\nstr_sort(lithuanian_words, locale = \"lt\")\n```\n"
  },
  {
    "path": "vignettes/regular-expressions.Rmd",
    "content": "---\ntitle: \"Regular expressions\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{Regular expressions}\n  %\\VignetteEngine{knitr::rmarkdown}\n  %\\VignetteEncoding{UTF-8}\n---\n\n```{r}\n#| label = \"setup\",\n#| include = FALSE\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#>\"\n)\nlibrary(stringr)\n```\n\nRegular expressions are a concise and flexible tool for describing patterns in strings. This vignette describes the key features of stringr's regular expressions, as implemented by [stringi](https://github.com/gagolews/stringi). It is not a tutorial, so if you're unfamiliar regular expressions, I'd recommend starting at <https://r4ds.had.co.nz/strings.html>. If you want to master the details, I'd recommend reading the classic [_Mastering Regular Expressions_](https://www.amazon.com/Mastering-Regular-Expressions-Jeffrey-Friedl/dp/0596528124) by Jeffrey E. F. Friedl. \n\nRegular expressions are the default pattern engine in stringr. That means when you use a pattern matching function with a bare string, it's equivalent to wrapping it in a call to `regex()`:\n\n```{r}\n#| eval = FALSE\n# The regular call:\nstr_extract(fruit, \"nana\")\n# Is shorthand for\nstr_extract(fruit, regex(\"nana\"))\n```\n\nYou will need to use `regex()` explicitly if you want to override the default options, as you'll see in examples below.\n\n## Basic matches\n\nThe simplest patterns match exact strings:\n\n```{r}\nx <- c(\"apple\", \"banana\", \"pear\")\nstr_extract(x, \"an\")\n```\n\nYou can perform a case-insensitive match using `ignore_case = TRUE`:\n    \n```{r}\nbananas <- c(\"banana\", \"Banana\", \"BANANA\")\nstr_detect(bananas, \"banana\")\nstr_detect(bananas, regex(\"banana\", ignore_case = TRUE))\n```\n\nThe next step up in complexity is `.`, which matches any character except a newline:\n\n```{r}\nstr_extract(x, \".a.\")\n```\n\nYou can allow `.` to match everything, including `\\n`, by setting `dotall = TRUE`:\n\n```{r}\nstr_detect(\"\\nX\\n\", \".X.\")\nstr_detect(\"\\nX\\n\", regex(\".X.\", dotall = TRUE))\n```\n\n## Escaping\n\nIf \"`.`\" matches any character, how do you match a literal \"`.`\"? You need to use an \"escape\" to tell the regular expression you want to match it exactly, not use its special behaviour. Like strings, regexps use the backslash, `\\`, to escape special behaviour. So to match an `.`, you need the regexp `\\.`. Unfortunately this creates a problem. We use strings to represent regular expressions, and `\\` is also used as an escape symbol in strings. So to create the regular expression `\\.` we need the string `\"\\\\.\"`. \n\n```{r}\n# To create the regular expression, we need \\\\\ndot <- \"\\\\.\"\n\n# But the expression itself only contains one:\nwriteLines(dot)\n\n# And this tells R to look for an explicit .\nstr_extract(c(\"abc\", \"a.c\", \"bef\"), \"a\\\\.c\")\n```\n\nIf `\\` is used as an escape character in regular expressions, how do you match a literal `\\`? Well you need to escape it, creating the regular expression `\\\\`. To create that regular expression, you need to use a string, which also needs to escape `\\`. That means to match a literal `\\` you need to write `\"\\\\\\\\\"` --- you need four backslashes to match one!\n\n```{r}\nx <- \"a\\\\b\"\nwriteLines(x)\n\nstr_extract(x, \"\\\\\\\\\")\n```\n\nIn this vignette, I use `\\.` to denote the regular expression, and `\"\\\\.\"` to denote the string that represents the regular expression.\n\nAn alternative quoting mechanism is `\\Q...\\E`: all the characters in `...` are treated as exact matches. This is useful if you want to exactly match user input as part of a regular expression.\n\n```{r}\nx <- c(\"a.b.c.d\", \"aeb\")\nstarts_with <- \"a.b\"\n\nstr_detect(x, paste0(\"^\", starts_with))\nstr_detect(x, paste0(\"^\\\\Q\", starts_with, \"\\\\E\"))\n```\n\n## Special characters\n\nEscapes also allow you to specify individual characters that are otherwise hard to type. You can specify individual unicode characters in five ways, either as a variable number of hex digits (four is most common), or by name:\n\n* `\\xhh`: 2 hex digits.\n\n* `\\x{hhhh}`: 1-6 hex digits.\n\n* `\\uhhhh`: 4 hex digits.\n\n* `\\Uhhhhhhhh`: 8 hex digits.\n\n* `\\N{name}`, e.g. `\\N{grinning face}` matches the basic smiling emoji.\n\nSimilarly, you can specify many common control characters:\n\n* `\\a`: bell.\n\n* `\\cX`: match a control-X character.\n\n* `\\e`: escape  (`\\u001B`).\n\n* `\\f`: form feed (`\\u000C`).\n\n* `\\n`: line feed (`\\u000A`).\n\n* `\\r`: carriage return (`\\u000D`).\n\n* `\\t`: horizontal tabulation (`\\u0009`).\n\n* `\\0ooo` match an octal character. 'ooo' is from one to three octal digits, \n  from 000 to 0377. The leading zero is required.\n\n(Many of these are only of historical interest and are only included here for the sake of completeness.)\n\n## Matching multiple characters\n\nThere are a number of patterns that match more than one character. You've already seen `.`, which matches any character (except a newline). A closely related operator is `\\X`, which matches a __grapheme cluster__, a set of individual elements that form a single symbol. For example, one way of representing \"á\" is as the letter \"a\" plus an accent: `.` will match the component \"a\", while `\\X` will match the complete symbol:\n    \n```{r}\nx <- \"a\\u0301\"\nstr_extract(x, \".\")\nstr_extract(x, \"\\\\X\")\n```\n\nThere are five other escaped pairs that match narrower classes of characters:\n   \n*   `\\d`: matches any digit. The complement, `\\D`, matches any character that \n    is not a decimal digit.\n\n    ```{r}\n    str_extract_all(\"1 + 2 = 3\", \"\\\\d+\")[[1]]\n    ```\n\n    Technically, `\\d` includes any character in the Unicode Category of Nd \n    (\"Number, Decimal Digit\"), which also includes numeric symbols from other \n    languages:\n    \n    ```{r}\n    # Some Laotian numbers\n    str_detect(\"១២៣\", \"\\\\d\")\n    ```\n    \n*   `\\s`: matches any whitespace. This includes tabs, newlines, form feeds, \n    and any character in the Unicode Z Category (which includes a variety of \n    space characters and other separators.). The complement, `\\S`, matches any\n    non-whitespace character.\n    \n    ```{r}\n    (text <- \"Some  \\t badly\\n\\t\\tspaced \\f text\")\n    str_replace_all(text, \"\\\\s+\", \" \")\n    ```\n\n*   `\\p{property name}` matches any character with specific unicode property,\n    like `\\p{Uppercase}` or `\\p{Diacritic}`. The complement, \n    `\\P{property name}`, matches all characters without the property.\n    A complete list of unicode properties can be found at\n    <http://www.unicode.org/reports/tr44/#Property_Index>.\n    \n    ```{r}\n    (text <- c('\"Double quotes\"', \"«Guillemet»\", \"“Fancy quotes”\"))\n    str_replace_all(text, \"\\\\p{quotation mark}\", \"'\")\n    ```\n\n*   `\\w` matches any \"word\" character, which includes alphabetic characters, \n    marks and decimal numbers. The complement, `\\W`, matches any non-word\n    character.\n    \n    ```{r}\n    str_extract_all(\"Don't eat that!\", \"\\\\w+\")[[1]]\n    str_split(\"Don't eat that!\", \"\\\\W\")[[1]]\n    ```\n    \n    Technically, `\\w` also matches connector punctuation, `\\u200c` (zero width\n    connector), and `\\u200d` (zero width joiner), but these are rarely seen in\n    the wild.\n\n*   `\\b` matches word boundaries, the transition between word and non-word \n    characters. `\\B` matches the opposite: boundaries that have either both\n    word or non-word characters on either side.\n    \n    ```{r}\n    str_replace_all(\"The quick brown fox\", \"\\\\b\", \"_\")\n    str_replace_all(\"The quick brown fox\", \"\\\\B\", \"_\")\n    ```\n\nYou can also create your own __character classes__ using `[]`:\n\n* `[abc]`: matches a, b, or c.\n* `[a-z]`: matches every character between a and z \n   (in Unicode code point order).\n* `[^abc]`: matches anything except a, b, or c.\n* `[\\^\\-]`: matches `^` or `-`.\n\nThere are a number of pre-built classes that you can use inside `[]`:\n\n* `[:punct:]`: punctuation.\n* `[:alpha:]`: letters.\n* `[:lower:]`: lowercase letters.\n* `[:upper:]`: upperclass letters.\n* `[:digit:]`: digits.\n* `[:xdigit:]`: hex digits.\n* `[:alnum:]`: letters and numbers.\n* `[:cntrl:]`: control characters.\n* `[:graph:]`: letters, numbers, and punctuation.\n* `[:print:]`: letters, numbers, punctuation, and whitespace.\n* `[:space:]`: space characters (basically equivalent to `\\s`).\n* `[:blank:]`: space and tab.\n\nThese all go inside the `[]` for character classes, i.e. `[[:digit:]AX]` matches all digits, A, and X.\n\nYou can also using Unicode properties, like `[\\p{Letter}]`, and various set operations, like `[\\p{Letter}--\\p{script=latin}]`. See `?\"stringi-search-charclass\"` for details.\n\n## Alternation\n\n`|` is the __alternation__ operator, which will pick between one or more possible matches. For example, `abc|def` will match `abc` or `def`:\n\n```{r}\nstr_detect(c(\"abc\", \"def\", \"ghi\"), \"abc|def\")\n```\n\nNote that the precedence for `|` is low: `abc|def` is equivalent to `(abc)|(def)` not `ab(c|d)ef`.\n\n## Grouping\n\nYou can use parentheses to override the default precedence rules:\n\n```{r}\nstr_extract(c(\"grey\", \"gray\"), \"gre|ay\")\nstr_extract(c(\"grey\", \"gray\"), \"gr(e|a)y\")\n```\n\nParentheses also define \"groups\" that you can refer to with __backreferences__, like `\\1`, `\\2` etc, and can be extracted with `str_match()`. For example, the following regular expression finds all fruits that have a repeated pair of letters:\n\n```{r}\npattern <- \"(..)\\\\1\"\nfruit %>% \n  str_subset(pattern)\n\nfruit %>% \n  str_subset(pattern) %>% \n  str_match(pattern)\n```\n\nYou can use `(?:...)`, the non-grouping parentheses, to control precedence but not capture the match in a group. This is slightly more efficient than capturing parentheses.\n\n```{r}\nstr_match(c(\"grey\", \"gray\"), \"gr(e|a)y\")\nstr_match(c(\"grey\", \"gray\"), \"gr(?:e|a)y\")\n```\n\nThis is most useful for more complex cases where you need to capture matches and control precedence independently.\n\nYou can use `(?<name>...)`, the named capture group, to provide a reference to the matched text. This is more readable and maintainable, especially with complex regular expressions, because you can reference the matched text by name instead of a potentially confusing numerical index. \n\n*Note: `<name>` should not include an underscore because they are not supported.*\n\n```{r}\ndate_string <- \"Today's date is 2025-09-19.\"\npattern <- \"(?<year>\\\\d{4})-(?<month>\\\\d{2})-(?<day>\\\\d{2})\"\nstr_match(date_string, pattern)\n```\n\nYou can then use `\\k<name>` to backreference the previously captured named group. It is an alternative to the standard numbered backreferences like `\\1` or `\\2`. \n\n```{r}\ntext <- \"This is is a test test with duplicates duplicates\"\npattern <- \"(?<word>\\\\b\\\\w+\\\\b)\\\\s+\\\\k<word>\"\nstr_subset(text, pattern)\nstr_match_all(text, pattern)\n```\n\n## Anchors\n\nBy default, regular expressions will match any part of a string. It's often useful to __anchor__ the regular expression so that it matches from the start or end of the string:\n\n* `^` matches the start of string. \n* `$` matches the end of the string.\n\n```{r}\nx <- c(\"apple\", \"banana\", \"pear\")\nstr_extract(x, \"^a\")\nstr_extract(x, \"a$\")\n```\n\nTo match a literal \"$\" or \"^\", you need to escape them, `\\$`, and `\\^`.\n\nFor multiline strings, you can use `regex(multiline = TRUE)`. This changes the behaviour of `^` and `$`, and introduces three new operators:\n\n* `^` now matches the start of each line. \n\n* `$` now matches the end of each line.\n\n* `\\A` matches the start of the input.\n\n* `\\z` matches the end of the input.\n\n* `\\Z` matches the end of the input, but before the final line terminator, \n  if it exists.\n\n```{r}\nx <- \"Line 1\\nLine 2\\nLine 3\\n\"\nstr_extract_all(x, \"^Line..\")[[1]]\nstr_extract_all(x, regex(\"^Line..\", multiline = TRUE))[[1]]\nstr_extract_all(x, regex(\"\\\\ALine..\", multiline = TRUE))[[1]]\n```\n\n## Repetition\n\nYou can control how many times a pattern matches with the repetition operators:\n\n* `?`: 0 or 1.\n* `+`: 1 or more.\n* `*`: 0 or more.\n\n```{r}\nx <- \"1888 is the longest year in Roman numerals: MDCCCLXXXVIII\"\nstr_extract(x, \"CC?\")\nstr_extract(x, \"CC+\")\nstr_extract(x, 'C[LX]+')\n```\n\nNote that the precedence of these operators is high, so you can write: `colou?r` to match either American or British spellings. That means most uses will need parentheses, like `bana(na)+`.\n\nYou can also specify the number of matches precisely:\n\n* `{n}`: exactly n\n* `{n,}`: n or more\n* `{n,m}`: between n and m\n\n```{r}\nstr_extract(x, \"C{2}\")\nstr_extract(x, \"C{2,}\")\nstr_extract(x, \"C{2,3}\")\n```\n\nBy default these matches are \"greedy\": they will match the longest string possible. You can make them \"lazy\", matching the shortest string possible by putting a `?` after them:\n\n* `??`: 0 or 1, prefer 0.\n* `+?`: 1 or more, match as few times as possible.\n* `*?`: 0 or more, match as few times as possible.\n* `{n,}?`: n or more, match as few times as possible.\n* `{n,m}?`: between n and m, , match as few times as possible, but at least n.\n\n```{r}\nstr_extract(x, c(\"C{2,3}\", \"C{2,3}?\"))\nstr_extract(x, c(\"C[LX]+\", \"C[LX]+?\"))\n```\n\nYou can also make the matches possessive by putting a `+` after them, which means that if later parts of the match fail, the repetition will not be re-tried with a smaller number of characters. This is an advanced feature used to improve performance in worst-case scenarios (called \"catastrophic backtracking\").\n\n* `?+`: 0 or 1, possessive.\n* `++`: 1 or more, possessive.\n* `*+`: 0 or more, possessive.\n* `{n}+`: exactly n, possessive.\n* `{n,}+`: n or more, possessive.\n* `{n,m}+`: between n and m, possessive.\n\nA related concept is the __atomic-match__ parenthesis, `(?>...)`. If a later match fails and the engine needs to back-track, an atomic match is kept as is: it succeeds or fails as a whole. Compare the following two regular expressions:\n\n```{r}\nstr_detect(\"ABC\", \"(?>A|.B)C\")\nstr_detect(\"ABC\", \"(?:A|.B)C\")\n```\n\nThe atomic match fails because it matches A, and then the next character is a C so it fails. The regular match succeeds because it matches A, but then C doesn't match, so it back-tracks and tries B instead.\n\n## Look arounds\n\nThese assertions look ahead or behind the current match without \"consuming\" any characters (i.e. changing the input position).\n\n* `(?=...)`: positive look-ahead assertion. Matches if `...` matches at the \n  current input.\n  \n* `(?!...)`: negative look-ahead assertion. Matches if `...` __does not__ \n  match at the current input.\n  \n* `(?<=...)`: positive look-behind assertion. Matches if `...` matches text \n  preceding the current position, with the last character of the match \n  being the character just before the current position. Length must be bounded  \n  (i.e. no `*` or `+`).\n\n* `(?<!...)`: negative look-behind assertion. Matches if `...` __does not__\n  match text preceding the current position. Length must be bounded  \n  (i.e. no `*` or `+`).\n\nThese are useful when you want to check that a pattern exists, but you don't want to include it in the result:\n\n```{r}\nx <- c(\"1 piece\", \"2 pieces\", \"3\")\nstr_extract(x, \"\\\\d+(?= pieces?)\")\n\ny <- c(\"100\", \"$400\")\nstr_extract(y, \"(?<=\\\\$)\\\\d+\")\n```\n\n## Comments\n\nThere are two ways to include comments in a regular expression. The first is with `(?#...)`:\n\n```{r}\nstr_detect(\"xyz\", \"x(?#this is a comment)\")\n```\n\nThe second is to use `regex(comments = TRUE)`. This form ignores spaces and newlines, and anything everything after `#`. To match a literal space, you'll need to escape it: `\"\\\\ \"`. This is a useful way of describing complex regular expressions:\n\n```{r}\nphone <- regex(\"\n  \\\\(?       # optional opening parens\n  (\\\\d{3})   # area code\n  \\\\)?       # optional closing parens\n  (?:-|\\\\ )? # optional dash or space\n  (\\\\d{3})   # another three numbers\n  (?:-|\\\\ )? # optional dash or space\n  (\\\\d{3})   # three more numbers\n  \", comments = TRUE)\n\nstr_match(c(\"514-791-8141\", \"(514) 791 8141\"), phone)\n```\n"
  },
  {
    "path": "vignettes/stringr.Rmd",
    "content": "---\ntitle: \"Introduction to stringr\"\noutput: rmarkdown::html_vignette\nvignette: >\n  %\\VignetteIndexEntry{Introduction to stringr}\n  %\\VignetteEngine{knitr::rmarkdown}\n  %\\VignetteEncoding{UTF-8}\n---\n\n```{r}\n#| include = FALSE\nlibrary(stringr)\nknitr::opts_chunk$set(\n  comment = \"#>\", \n  collapse = TRUE\n)\n```\n\nThere are four main families of functions in stringr: \n\n1.  Character manipulation: these functions allow you to manipulate \n    individual characters within the strings in character vectors.\n   \n1.  Whitespace tools to add, remove, and manipulate whitespace.\n\n1.  Locale sensitive operations whose operations will vary from locale\n    to locale.\n    \n1.  Pattern matching functions. These recognise four engines of\n    pattern description. The most common is regular expressions, but there\n    are three other tools.\n\n## Getting and setting individual characters\n\nYou can get the length of the string with `str_length()`:\n\n```{r}\nstr_length(\"abc\")\n```\n\nThis is now equivalent to the base R function `nchar()`. Previously it was needed to work around issues with `nchar()` such as the fact that it returned 2 for `nchar(NA)`. This has been fixed as of R 3.3.0, so it is no longer so important.\n\nYou can access individual character using `str_sub()`. It takes three arguments: a character vector, a `start` position and an `end` position. Either position can either be a positive integer, which counts from the left, or a negative integer which counts from the right. The positions are inclusive, and if longer than the string, will be silently truncated.\n\n```{r}\nx <- c(\"abcdef\", \"ghifjk\")\n\n# The 3rd letter\nstr_sub(x, 3, 3)\n\n# The 2nd to 2nd-to-last character\nstr_sub(x, 2, -2)\n\n```\n\nYou can also use `str_sub()` to modify strings:\n\n```{r}\nstr_sub(x, 3, 3) <- \"X\"\nx\n```\n\nTo duplicate individual strings, you can use `str_dup()`:\n\n```{r}\nstr_dup(x, c(2, 3))\n```\n\n## Whitespace\n\nThree functions add, remove, or modify whitespace:\n\n1. `str_pad()` pads a string to a fixed length by adding extra whitespace on \n    the left, right, or both sides.\n    \n    ```{r}\n    x <- c(\"abc\", \"defghi\")\n    str_pad(x, 10) # default pads on left\n    str_pad(x, 10, \"both\")\n    ```\n    \n    (You can pad with other characters by using the `pad` argument.)\n    \n    `str_pad()` will never make a string shorter:\n    \n    ```{r}\n    str_pad(x, 4)\n    ```\n    \n    So if you want to ensure that all strings are the same length (often useful\n    for print methods), combine `str_pad()` and `str_trunc()`:\n    \n    ```{r}\n    x <- c(\"Short\", \"This is a long string\")\n    \n    x %>% \n      str_trunc(10) %>% \n      str_pad(10, \"right\")\n    ```\n\n1.  The opposite of `str_pad()` is `str_trim()`, which removes leading and \n    trailing whitespace:\n    \n    ```{r}\n    x <- c(\"  a   \", \"b   \",  \"   c\")\n    str_trim(x)\n    str_trim(x, \"left\")\n    ```\n\n1.  You can use `str_wrap()` to modify existing whitespace in order to wrap\n    a paragraph of text, such that the length of each line is as similar as \n    possible. \n    \n    ```{r}\n    jabberwocky <- str_c(\n      \"`Twas brillig, and the slithy toves \",\n      \"did gyre and gimble in the wabe: \",\n      \"All mimsy were the borogoves, \",\n      \"and the mome raths outgrabe. \"\n    )\n    cat(str_wrap(jabberwocky, width = 40))\n    ```\n\n## Locale sensitive\n\nA handful of stringr functions are locale-sensitive: they will perform differently in different regions of the world. These functions are case transformation functions:\n\n```{r}\nx <- \"I like horses.\"\nstr_to_upper(x)\nstr_to_title(x)\n\nstr_to_lower(x)\n# Turkish has two sorts of i: with and without the dot\nstr_to_lower(x, \"tr\")\n```\n\nString ordering and sorting:\n\n```{r}\nx <- c(\"y\", \"i\", \"k\")\nstr_order(x)\n\nstr_sort(x)\n# In Lithuanian, y comes between i and k\nstr_sort(x, locale = \"lt\")\n```\n\nThe locale always defaults to English to ensure that the default behaviour is identical across systems. Locales always include a two letter ISO-639-1 language code (like \"en\" for English or \"zh\" for Chinese), and optionally a ISO-3166 country code (like \"en_UK\" vs \"en_US\"). You can see a complete list of available locales by running `stringi::stri_locale_list()`.\n\n## Pattern matching\n\nThe vast majority of stringr functions work with patterns. These are parameterised by the task they perform and the types of patterns they match.\n\n### Tasks\n\nEach pattern matching function has the same first two arguments, a character vector of `string`s to process and a single `pattern` to match. stringr provides pattern matching functions to **detect**, **locate**, **extract**, **match**, **replace**, and **split** strings. I'll illustrate how they work with some strings and a regular expression designed to match (US) phone numbers:\n\n```{r}\nstrings <- c(\n  \"apple\", \n  \"219 733 8965\", \n  \"329-293-8753\", \n  \"Work: 579-499-7527; Home: 543.355.3679\"\n)\nphone <- \"([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})\"\n```\n\n-   `str_detect()` detects the presence or absence of a pattern and returns a \n    logical vector (similar to `grepl()`). `str_subset()` returns the elements\n    of a character vector that match a regular expression (similar to `grep()` \n    with `value = TRUE`)`.\n    \n    ```{r}\n    # Which strings contain phone numbers?\n    str_detect(strings, phone)\n    str_subset(strings, phone)\n    ```\n\n-  `str_count()` counts the number of matches:\n\n    ```{r}\n    # How many phone numbers in each string?\n    str_count(strings, phone)\n    ```\n\n-   `str_locate()` locates the **first** position of a pattern and returns a numeric \n    matrix with columns start and end. `str_locate_all()` locates all matches, \n    returning a list of numeric matrices. Similar to `regexpr()` and `gregexpr()`.\n\n    ```{r}\n    # Where in the string is the phone number located?\n    (loc <- str_locate(strings, phone))\n    str_locate_all(strings, phone)\n    ```\n\n-   `str_extract()` extracts text corresponding to the **first** match, returning a \n    character vector. `str_extract_all()` extracts all matches and returns a \n    list of character vectors.\n\n    ```{r}\n    # What are the phone numbers?\n    str_extract(strings, phone)\n    str_extract_all(strings, phone)\n    str_extract_all(strings, phone, simplify = TRUE)\n    ```\n\n-   `str_match()` extracts capture groups formed by `()` from the **first** match. \n    It returns a character matrix with one column for the complete match and \n    one column for each group. `str_match_all()` extracts capture groups from \n    all matches and returns a list of character matrices. Similar to \n    `regmatches()`.\n\n    ```{r}\n    # Pull out the three components of the match\n    str_match(strings, phone)\n    str_match_all(strings, phone)\n    ```\n\n-   `str_replace()` replaces the **first** matched pattern and returns a character\n    vector. `str_replace_all()` replaces all matches. Similar to `sub()` and \n    `gsub()`.\n\n    ```{r}\n    str_replace(strings, phone, \"XXX-XXX-XXXX\")\n    str_replace_all(strings, phone, \"XXX-XXX-XXXX\")\n    ```\n\n-   `str_split_fixed()` splits a string into a **fixed** number of pieces based \n    on a pattern and returns a character matrix. `str_split()` splits a string \n    into a **variable** number of pieces and returns a list of character vectors.\n    \n    ```{r}\n    str_split(\"a-b-c\", \"-\")\n    str_split_fixed(\"a-b-c\", \"-\", n = 2)\n    ```\n\n### Engines\n\nThere are four main engines that stringr can use to describe patterns:\n\n* Regular expressions, the default, as shown above, and described in\n  `vignette(\"regular-expressions\")`. \n  \n* Fixed bytewise matching, with `fixed()`.\n\n* Locale-sensitive character matching, with `coll()`\n\n* Text boundary analysis with `boundary()`.\n\n#### Fixed matches\n\n`fixed(x)` only matches the exact sequence of bytes specified by `x`. This is a very limited \"pattern\", but the restriction can make matching much faster. Beware using `fixed()` with non-English data. It is problematic because there are often multiple ways of representing the same character. For  example, there are two ways to define \"á\": either as a single character or as an \"a\" plus an accent:\n\n```{r}\na1 <- \"\\u00e1\"\na2 <- \"a\\u0301\"\nc(a1, a2)\na1 == a2\n```\n\nThey render identically, but because they're defined differently, \n`fixed()` doesn't find a match. Instead, you can use `coll()`, explained\nbelow, to respect human character comparison rules:\n\n```{r}\nstr_detect(a1, fixed(a2))\nstr_detect(a1, coll(a2))\n```\n    \n#### Collation search\n    \n`coll(x)` looks for a match to `x` using human-language **coll**ation rules, and is particularly important if you want to do case insensitive matching. Collation rules differ around the world, so you'll also need to supply a `locale` parameter.\n\n```{r}\ni <- c(\"I\", \"İ\", \"i\", \"ı\")\ni\n\nstr_subset(i, coll(\"i\", ignore_case = TRUE))\nstr_subset(i, coll(\"i\", ignore_case = TRUE, locale = \"tr\"))\n```\n\nThe downside of `coll()` is speed. Because the rules for recognising which characters are the same are complicated, `coll()` is relatively slow compared to `regex()` and `fixed()`. Note that when both `fixed()` and `regex()` have `ignore_case` arguments, they perform a much simpler comparison than `coll()`.\n\n#### Boundary\n\n`boundary()` matches boundaries between characters, lines, sentences or words. It's most useful with `str_split()`, but can be used with all pattern matching functions:\n\n```{r}\nx <- \"This is a sentence.\"\nstr_split(x, boundary(\"word\"))\nstr_count(x, boundary(\"word\"))\nstr_extract_all(x, boundary(\"word\"))\n```\n\nBy convention, `\"\"` is treated as `boundary(\"character\")`:\n\n```{r}\nstr_split(x, \"\")\nstr_count(x, \"\")\n```\n"
  }
]