diff --git a/NEWS.md b/NEWS.md index b19a2d9c7..7dfc74fdb 100644 --- a/NEWS.md +++ b/NEWS.md @@ -63,7 +63,8 @@ - In `$dt$convert_time_zone()` and `$dt$replace_time_zone()`, the `tz` argument is renamed to `time_zone` (#944). - In `$str$strptime()`, the argument `datatype` is renamed to `dtype` (#939). - - In `$str$parse_int()`, argument `radix` is renamed to `base` (#1034). + - In `$str$to_integer()` (renamed from `$str$parse_int()`), argument `radix` is + renamed to `base` (#1038). 2. Change in the way arguments are passed: @@ -84,6 +85,8 @@ the `literal` argument must be named (#987). - In `$str$strptime()`, `$str$to_date()`, `$str$to_datetime()`, and `$str$to_time()`, all arguments (except the first one) must be named (#939). + - In `$str$to_integer()` (renamed from `$str$parse_int()`), all arguments + must be named (#1038). - In `pl$date_range()`, the arguments `closed`, `time_unit`, and `time_zone` must be named (#950). - In `$set_sorted()` and `$sort_by()`, argument `descending` must be named @@ -136,7 +139,8 @@ only accepts `"auto"`, `"columns"`, `"row_groups"`, and `"none"`. Previously, it also accepted upper-case notation of `"auto"`, `"columns"`, `"none"`, and `"RowGroups"` instead of `"row_groups"` (#1033). - + - In `$str$to_integer()` (renamed from `$str$parse_int()`), the default + value of `base` is changed from `2` to `10` (#1038). - The usage of `pl$date_range()` to create a range of `Datetime` data type is deprecated. `pl$date_range()` will always create a range of `Date` data type @@ -154,6 +158,7 @@ - The following deprecated functions are now removed: `pl$threadpool_size()`, `$with_row_count()`, `$with_row_count()` (#965). - In `$group_by_dynamic()`, the first datapoint is always preserved (#1034). +- `$str$parse_int()` is renamed to `$str$to_integer()` (#1038). ### New features diff --git a/R/expr__string.R b/R/expr__string.R index 38a5e3e74..2f709fad6 100644 --- a/R/expr__string.R +++ b/R/expr__string.R @@ -391,7 +391,7 @@ ExprStr_strip_chars_end = function(matches = NULL) { #' some_floats_expr$cast(pl$Int64)$cast(pl$String)$str$zfill(5)$to_r() ExprStr_zfill = function(alignment) { .pr$Expr$str_zfill(self, alignment) |> - unwrap("in str$zfill():") + unwrap("in $str$zfill():") } @@ -409,7 +409,7 @@ ExprStr_zfill = function(alignment) { #' df$select(pl$col("a")$str$pad_end(8, "*")) ExprStr_pad_end = function(width, fillchar = " ") { .pr$Expr$str_pad_end(self, width, fillchar) |> - unwrap("in str$pad_end(): ") + unwrap("in $str$pad_end(): ") } @@ -425,7 +425,7 @@ ExprStr_pad_end = function(width, fillchar = " ") { #' df$select(pl$col("a")$str$pad_start(8, "*")) ExprStr_pad_start = function(width, fillchar = " ") { .pr$Expr$str_pad_start(self, width, fillchar) |> - unwrap("in str$pad_start(): ") + unwrap("in $str$pad_start(): ") } @@ -528,7 +528,7 @@ ExprStr_starts_with = function(sub) { #' df$select(pl$col("json_val")$str$json_decode(dtype)) ExprStr_json_decode = function(dtype, infer_schema_length = 100) { .pr$Expr$str_json_decode(self, dtype, infer_schema_length) |> - unwrap("in str$json_decode():") + unwrap("in $str$json_decode():") } #' Extract the first match of JSON string with the provided JSONPath expression @@ -549,7 +549,7 @@ ExprStr_json_decode = function(dtype, infer_schema_length = 100) { #' df$select(pl$col("json_val")$str$json_path_match("$.a")) ExprStr_json_path_match = function(json_path) { .pr$Expr$str_json_path_match(self, json_path) |> - unwrap("in str$json_path_match(): ") + unwrap("in $str$json_path_match(): ") } @@ -636,7 +636,7 @@ ExprStr_encode = function(encoding) { #' ) ExprStr_extract = function(pattern, group_index) { .pr$Expr$str_extract(self, pattern, group_index) |> - unwrap("in str$extract(): ") + unwrap("in $str$extract(): ") } @@ -699,7 +699,7 @@ ExprStr_count_matches = function(pattern, ..., literal = FALSE) { ExprStr_split = function(by, inclusive = FALSE) { unwrap( .pr$Expr$str_split(self, result(by), result(inclusive)), - context = "in str$split():" + context = "in $str$split():" ) } @@ -723,7 +723,7 @@ ExprStr_split = function(by, inclusive = FALSE) { ExprStr_split_exact = function(by, n, inclusive = FALSE) { unwrap( .pr$Expr$str_split_exact(self, by, result(n), result(inclusive)), - context = "in str$split_exact():" + context = "in $str$split_exact():" ) } @@ -749,7 +749,7 @@ ExprStr_split_exact = function(by, n, inclusive = FALSE) { #' s3 = pl$col("s")$str$splitn(by = "_", 3) #' ) ExprStr_splitn = function(by, n) { - .pr$Expr$str_splitn(self, result(by), result(n)) |> unwrap("in str$splitn():") + .pr$Expr$str_splitn(self, result(by), result(n)) |> unwrap("in $str$splitn():") } @@ -850,7 +850,7 @@ ExprStr_replace_all = function(pattern, value, ..., literal = FALSE) { #' ) ExprStr_slice = function(offset, length = NULL) { .pr$Expr$str_slice(self, result(offset), result(length)) |> - unwrap("in str$slice():") + unwrap("in $str$slice():") } #' Returns a column with a separate row for every string character @@ -862,29 +862,31 @@ ExprStr_slice = function(offset, length = NULL) { #' df$select(pl$col("a")$str$explode()) ExprStr_explode = function() { .pr$Expr$str_explode(self) |> - unwrap("in str$explode():") + unwrap("in $str$explode():") } -# TODO: rename to `to_integer` -#' Parse integers with base radix from strings + +#' Convert a String column into an Int64 column with base radix #' -#' @description Parse integers with base 2 by default. -#' @keywords ExprStr -#' @param base Positive integer which is the base of the string we are parsing. -#' Default is 2. -#' @param strict If `TRUE` (default), integer overflow will raise an error. -#' Otherwise, they will be converted to `null`. -#' @return Expr: Series of dtype i32. +#' @param ... Ignored. +#' @param base A positive integer or expression which is the base of the string +#' we are parsing. Characters are parsed as column names. Default: `10L`. +#' @param strict A logical. If `TRUE` (default), parsing errors or integer overflow will +#' raise an error. If `FALSE`, silently convert to `null`. +#' @return [Expression][Expr_class] of data type `Int64`. #' @examples -#' df = pl$DataFrame(bin = c("110", "101", "010")) -#' df$select(pl$col("bin")$str$parse_int()) -#' df$select(pl$col("bin")$str$parse_int(10)) -#' -#' # Convert to null if the string is not a valid integer when `strict = FALSE` -#' df = pl$DataFrame(x = c("1", "2", "foo")) -#' df$select(pl$col("x")$str$parse_int(10, FALSE)) -ExprStr_parse_int = function(base = 2, strict = TRUE) { - .pr$Expr$str_parse_int(self, base, strict) |> unwrap("in str$parse_int():") +#' df = pl$DataFrame(bin = c("110", "101", "010", "invalid")) +#' df$with_columns( +#' parsed = pl$col("bin")$str$to_integer(base = 2, strict = FALSE) +#' ) +#' +#' df = pl$DataFrame(hex = c("fa1e", "ff00", "cafe", NA)) +#' df$with_columns( +#' parsed = pl$col("hex")$str$to_integer(base = 16, strict = TRUE) +#' ) +ExprStr_to_integer = function(..., base = 10L, strict = TRUE) { + .pr$Expr$str_to_integer(self, base, strict) |> + unwrap("in $str$to_integer():") } #' Returns string values in reversed order @@ -896,7 +898,7 @@ ExprStr_parse_int = function(base = 2, strict = TRUE) { #' df$with_columns(reversed = pl$col("text")$str$reverse()) ExprStr_reverse = function() { .pr$Expr$str_reverse(self) |> - unwrap("in str$reverse():") + unwrap("in $str$reverse():") } #' Use the aho-corasick algorithm to find matches @@ -924,7 +926,7 @@ ExprStr_reverse = function() { #' ) ExprStr_contains_any = function(patterns, ..., ascii_case_insensitive = FALSE) { .pr$Expr$str_contains_any(self, patterns, ascii_case_insensitive) |> - unwrap("in str$contains_any():") + unwrap("in $str$contains_any():") } #' Use the aho-corasick algorithm to replace many matches @@ -962,7 +964,7 @@ ExprStr_contains_any = function(patterns, ..., ascii_case_insensitive = FALSE) { #' ) ExprStr_replace_many = function(patterns, replace_with, ascii_case_insensitive = FALSE) { .pr$Expr$str_replace_many(self, patterns, replace_with, ascii_case_insensitive) |> - unwrap("in str$replace_many():") + unwrap("in $str$replace_many():") } @@ -1000,7 +1002,7 @@ ExprStr_replace_many = function(patterns, replace_with, ascii_case_insensitive = #' )$unnest("captures") ExprStr_extract_groups = function(pattern) { .pr$Expr$str_extract_groups(self, pattern) |> - unwrap("in str$extract_groups():") + unwrap("in $str$extract_groups():") } #' Return the index position of the first substring matching a pattern @@ -1024,5 +1026,5 @@ ExprStr_extract_groups = function(pattern) { #' ) ExprStr_find = function(pattern, ..., literal = FALSE, strict = TRUE) { .pr$Expr$str_find(self, pattern, literal, strict) |> - unwrap("in str$find():") + unwrap("in $str$find():") } diff --git a/R/extendr-wrappers.R b/R/extendr-wrappers.R index f45195176..b6120a72e 100644 --- a/R/extendr-wrappers.R +++ b/R/extendr-wrappers.R @@ -1054,7 +1054,7 @@ RPolarsExpr$str_slice <- function(offset, length) .Call(wrap__RPolarsExpr__str_s RPolarsExpr$str_explode <- function() .Call(wrap__RPolarsExpr__str_explode, self) -RPolarsExpr$str_parse_int <- function(base, strict) .Call(wrap__RPolarsExpr__str_parse_int, self, base, strict) +RPolarsExpr$str_to_integer <- function(base, strict) .Call(wrap__RPolarsExpr__str_to_integer, self, base, strict) RPolarsExpr$str_reverse <- function() .Call(wrap__RPolarsExpr__str_reverse, self) diff --git a/man/ExprStr_parse_int.Rd b/man/ExprStr_parse_int.Rd deleted file mode 100644 index fdf599e16..000000000 --- a/man/ExprStr_parse_int.Rd +++ /dev/null @@ -1,31 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/expr__string.R -\name{ExprStr_parse_int} -\alias{ExprStr_parse_int} -\title{Parse integers with base radix from strings} -\usage{ -ExprStr_parse_int(base = 2, strict = TRUE) -} -\arguments{ -\item{base}{Positive integer which is the base of the string we are parsing. -Default is 2.} - -\item{strict}{If \code{TRUE} (default), integer overflow will raise an error. -Otherwise, they will be converted to \code{null}.} -} -\value{ -Expr: Series of dtype i32. -} -\description{ -Parse integers with base 2 by default. -} -\examples{ -df = pl$DataFrame(bin = c("110", "101", "010")) -df$select(pl$col("bin")$str$parse_int()) -df$select(pl$col("bin")$str$parse_int(10)) - -# Convert to null if the string is not a valid integer when `strict = FALSE` -df = pl$DataFrame(x = c("1", "2", "foo")) -df$select(pl$col("x")$str$parse_int(10, FALSE)) -} -\keyword{ExprStr} diff --git a/man/ExprStr_to_integer.Rd b/man/ExprStr_to_integer.Rd new file mode 100644 index 000000000..b4e5c8513 --- /dev/null +++ b/man/ExprStr_to_integer.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/expr__string.R +\name{ExprStr_to_integer} +\alias{ExprStr_to_integer} +\title{Convert a String column into an Int64 column with base radix} +\usage{ +ExprStr_to_integer(..., base = 10L, strict = TRUE) +} +\arguments{ +\item{...}{Ignored.} + +\item{base}{A positive integer or expression which is the base of the string +we are parsing. Characters are parsed as column names. Default: \code{10L}.} + +\item{strict}{A logical. If \code{TRUE} (default), parsing errors or integer overflow will +raise an error. If \code{FALSE}, silently convert to \code{null}.} +} +\value{ +\link[=Expr_class]{Expression} of data type \code{Int64}. +} +\description{ +Convert a String column into an Int64 column with base radix +} +\examples{ +df = pl$DataFrame(bin = c("110", "101", "010", "invalid")) +df$with_columns( + parsed = pl$col("bin")$str$to_integer(base = 2, strict = FALSE) +) + +df = pl$DataFrame(hex = c("fa1e", "ff00", "cafe", NA)) +df$with_columns( + parsed = pl$col("hex")$str$to_integer(base = 16, strict = TRUE) +) +} diff --git a/src/rust/src/lazy/dsl.rs b/src/rust/src/lazy/dsl.rs index fee626b35..a186f42e9 100644 --- a/src/rust/src/lazy/dsl.rs +++ b/src/rust/src/lazy/dsl.rs @@ -2307,14 +2307,15 @@ impl RPolarsExpr { Ok(self.0.clone().str().explode().into()) } - // TODO: rename to `str_to_integer` - pub fn str_parse_int(&self, base: Robj, strict: Robj) -> RResult { + pub fn str_to_integer(&self, base: Robj, strict: Robj) -> RResult { + let base = robj_to!(PLExprCol, base)?; + let strict = robj_to!(bool, strict)?; Ok(self .0 .clone() .str() - .to_integer(robj_to!(PLExprCol, base)?, robj_to!(bool, strict)?) - .with_fmt("str.parse_int") + .to_integer(base, strict) + .with_fmt("str.to_integer") .into()) } diff --git a/tests/testthat/_snaps/after-wrappers.md b/tests/testthat/_snaps/after-wrappers.md index e38cb3ee5..3941605f6 100644 --- a/tests/testthat/_snaps/after-wrappers.md +++ b/tests/testthat/_snaps/after-wrappers.md @@ -415,14 +415,14 @@ [277] "str_json_decode" "str_json_path_match" [279] "str_len_bytes" "str_len_chars" [281] "str_pad_end" "str_pad_start" - [283] "str_parse_int" "str_replace" - [285] "str_replace_all" "str_replace_many" - [287] "str_reverse" "str_slice" - [289] "str_split" "str_split_exact" - [291] "str_splitn" "str_starts_with" - [293] "str_strip_chars" "str_strip_chars_end" - [295] "str_strip_chars_start" "str_to_date" - [297] "str_to_datetime" "str_to_lowercase" + [283] "str_replace" "str_replace_all" + [285] "str_replace_many" "str_reverse" + [287] "str_slice" "str_split" + [289] "str_split_exact" "str_splitn" + [291] "str_starts_with" "str_strip_chars" + [293] "str_strip_chars_end" "str_strip_chars_start" + [295] "str_to_date" "str_to_datetime" + [297] "str_to_integer" "str_to_lowercase" [299] "str_to_time" "str_to_titlecase" [301] "str_to_uppercase" "str_zfill" [303] "struct_field_by_name" "struct_rename_fields" diff --git a/tests/testthat/test-expr_string.R b/tests/testthat/test-expr_string.R index 4c7c45900..0552c9252 100644 --- a/tests/testthat/test-expr_string.R +++ b/tests/testthat/test-expr_string.R @@ -685,28 +685,35 @@ test_that("str$str_explode", { }) -test_that("str$parse_int", { +test_that("str$to_integer", { expect_identical( - pl$lit(c("110", "101", "010"))$str$parse_int(2)$to_r(), + pl$lit(c("110", "101", "010"))$str$to_integer(base = 2)$to_r(), c(6, 5, 2) ) expect_identical( - pl$lit(c("110", "101", "010"))$str$parse_int()$to_r(), - c(6, 5, 2) + pl$lit(c("110", "101", "010"))$str$to_integer()$to_r(), + c(110, 101, 10) ) expect_identical( - pl$lit(c("110", "101", "010"))$str$parse_int(10)$to_r(), + pl$lit(c("110", "101", "010"))$str$to_integer(base = 10)$to_r(), c(110, 101, 10) ) expect_identical( - pl$lit(c("110", "101", "hej"))$str$parse_int(10, FALSE)$to_r(), + pl$lit(c("110", "101", "hej"))$str$to_integer(base = 10, strict = FALSE)$to_r(), c(110, 101, NA) ) - expect_grepl_error(pl$lit("foo")$str$parse_int()$to_r(), "strict integer parsing failed for 1 value") + expect_grepl_error(pl$lit("foo")$str$to_integer()$to_r(), "strict integer parsing failed for 1 value") + + expect_identical( + pl$DataFrame(base = c(2, 10), str = "10")$select( + pl$col("str")$str$to_integer(base = "base") + )$to_list()[[1]], + c(2, 10) + ) }) test_that("str$reverse()", {