From b8bbbfd652062062ffd1ba5cd39aca7d2831e1c4 Mon Sep 17 00:00:00 2001 From: Bill Denney Date: Wed, 22 Dec 2021 11:35:18 -0500 Subject: [PATCH] add iso8601_regexp function family and make_param_label function --- NAMESPACE | 7 + R/iso8601_regexp.R | 240 ++++++++++++++++++++--- R/make_param_label.R | 29 +++ man/is_ISO8601_calendar_date.Rd | 4 +- man/is_ISO8601_calendar_datetime.Rd | 12 +- man/is_ISO8601_ordinal_datetime.Rd | 32 +++ man/is_ISO8601_time.Rd | 4 +- man/is_ISO8601_timezone.Rd | 4 +- man/is_ISO8601_week_datetime.Rd | 32 +++ man/make_param_label.Rd | 36 ++++ man/pattern_ISO8601_any_date.Rd | 50 +++++ man/pattern_ISO8601_any_datetime.Rd | 34 ++++ man/pattern_ISO8601_calendar_date.Rd | 4 + man/pattern_ISO8601_calendar_datetime.Rd | 4 + man/pattern_ISO8601_calendar_year.Rd | 4 + man/pattern_ISO8601_date_builder.Rd | 3 +- man/pattern_ISO8601_ordinal_date.Rd | 6 +- man/pattern_ISO8601_ordinal_datetime.Rd | 34 ++++ man/pattern_ISO8601_time.Rd | 4 + man/pattern_ISO8601_timezone.Rd | 4 + man/pattern_ISO8601_week_date.Rd | 8 +- man/pattern_ISO8601_week_datetime.Rd | 34 ++++ tests/testthat/test-iso8601_regexp.R | 14 +- tests/testthat/test-make_param_label.R | 54 +++++ 24 files changed, 610 insertions(+), 47 deletions(-) create mode 100644 R/make_param_label.R create mode 100644 man/is_ISO8601_ordinal_datetime.Rd create mode 100644 man/is_ISO8601_week_datetime.Rd create mode 100644 man/make_param_label.Rd create mode 100644 man/pattern_ISO8601_any_date.Rd create mode 100644 man/pattern_ISO8601_any_datetime.Rd create mode 100644 man/pattern_ISO8601_ordinal_datetime.Rd create mode 100644 man/pattern_ISO8601_week_datetime.Rd create mode 100644 tests/testthat/test-make_param_label.R diff --git a/NAMESPACE b/NAMESPACE index ef4ca83..4c769a9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -16,17 +16,24 @@ export(import_sdtm_file) export(is_ISO8601_calendar_date) export(is_ISO8601_calendar_datetime) export(is_ISO8601_ordinal_date) +export(is_ISO8601_ordinal_datetime) export(is_ISO8601_time) export(is_ISO8601_timezone) export(is_ISO8601_week_date) +export(is_ISO8601_week_datetime) +export(make_param_label) export(merge_supp) +export(pattern_ISO8601_any_date) +export(pattern_ISO8601_any_datetime) export(pattern_ISO8601_calendar_date) export(pattern_ISO8601_calendar_datetime) export(pattern_ISO8601_calendar_year) export(pattern_ISO8601_ordinal_date) +export(pattern_ISO8601_ordinal_datetime) export(pattern_ISO8601_time) export(pattern_ISO8601_timezone) export(pattern_ISO8601_week_date) +export(pattern_ISO8601_week_datetime) export(scale_x_VISITDY) export(sdtm_dtc_to_datetime) export(sdtm_first_dose) diff --git a/R/iso8601_regexp.R b/R/iso8601_regexp.R index 3f2fedc..2ee94db 100644 --- a/R/iso8601_regexp.R +++ b/R/iso8601_regexp.R @@ -1,7 +1,7 @@ # Boolean functions #### -#' Determine if a string matches an ISO 8601 date/time using standard calendar -#' date notation +#' Determine if a string matches an ISO 8601 date/time using calendar date +#' notation #' #' @param x A vector of character strings to test #' @inheritDotParams pattern_ISO8601_calendar_datetime @@ -14,6 +14,32 @@ is_ISO8601_calendar_datetime <- function(x, ...) { ) } +#' Determine if a string matches an ISO 8601 date/time using week date notation +#' +#' @param x A vector of character strings to test +#' @inheritDotParams pattern_ISO8601_week_datetime +#' @family ISO8601 String checking +#' @export +is_ISO8601_week_datetime <- function(x, ...) { + grepl( + x=as.character(x), + pattern=make_full_pattern(pattern_ISO8601_week_datetime(...)) + ) +} + +#' Determine if a string matches an ISO 8601 date/time using ordinal date notation +#' +#' @param x A vector of character strings to test +#' @inheritDotParams pattern_ISO8601_ordinal_datetime +#' @family ISO8601 String checking +#' @export +is_ISO8601_ordinal_datetime <- function(x, ...) { + grepl( + x=as.character(x), + pattern=make_full_pattern(pattern_ISO8601_ordinal_datetime(...)) + ) +} + #' Determine if a string is an ISO 8601 calendar date #' #' @inheritParams is_ISO8601_calendar_datetime @@ -74,6 +100,24 @@ is_ISO8601_timezone <- function(x) { # Date/time functions #### +#' Generate a regular expression matching any ISO8601 date format with time +#' +#' @param truncated Should the date/time be allowed to be truncated? An integer +#' indicating the highest required precision (0=second is required, 1=minute, +#' 2=hour, 3=day, 4=month or week, 5=year, 6=none). A value of 6 will allow an empty +#' string to match. +#' @param ... Passed to \code{pattern_ISO8601_any_date()} and +#' \code{pattern_ISO8601_time()} +#' @family ISO8601 patterns +#' @export +pattern_ISO8601_any_datetime <- function(truncated=0, ...) { + pattern_ISO8601_datetime_builder( + truncated=truncated, + ..., + pattern_date_fun=pattern_ISO8601_any_date + ) +} + #' Generate a regular expression matching an ISO8601 calendar date with time #' #' @param truncated Should the date/time be allowed to be truncated? An integer @@ -85,6 +129,50 @@ is_ISO8601_timezone <- function(x) { #' @family ISO8601 patterns #' @export pattern_ISO8601_calendar_datetime <- function(truncated=0, ...) { + pattern_ISO8601_datetime_builder( + truncated=truncated, + ..., + pattern_date_fun=pattern_ISO8601_calendar_date + ) +} + +#' Generate a regular expression matching an ISO8601 week date with time +#' +#' @param truncated Should the date/time be allowed to be truncated? An integer +#' indicating the highest required precision (0=second is required, 1=minute, +#' 2=hour, 3=day, 4=week, 5=year, 6=none). A value of 6 will allow an empty +#' string to match. +#' @param ... Passed to \code{pattern_ISO8601_week_date()} and +#' \code{pattern_ISO8601_time()} +#' @family ISO8601 patterns +#' @export +pattern_ISO8601_week_datetime <- function(truncated=0, ...) { + pattern_ISO8601_datetime_builder( + truncated=truncated, + ..., + pattern_date_fun=pattern_ISO8601_week_date + ) +} + +#' Generate a regular expression matching an ISO8601 ordinal date with time +#' +#' @param truncated Should the date/time be allowed to be truncated? An integer +#' indicating the highest required precision (0=second is required, 1=minute, +#' 2=hour, 3 or 4=day, 5=year, 6=none). A value of 6 will allow an empty +#' string to match. +#' @param ... Passed to \code{pattern_ISO8601_week_date()} and +#' \code{pattern_ISO8601_time()} +#' @family ISO8601 patterns +#' @export +pattern_ISO8601_ordinal_datetime <- function(truncated=0, ...) { + pattern_ISO8601_datetime_builder( + truncated=truncated, + ..., + pattern_date_fun=pattern_ISO8601_ordinal_date + ) +} + +pattern_ISO8601_datetime_builder <- function(truncated, ..., pattern_date_fun) { stopifnot(is.numeric(truncated)) stopifnot(length(truncated) == 1) stopifnot(truncated >= 0 & truncated <= 6) @@ -96,34 +184,65 @@ pattern_ISO8601_calendar_datetime <- function(truncated=0, ...) { pattern_time, allow_truncation=truncated >= 3 ) - pattern_ISO8601_calendar_date( + pattern_date_fun( truncated=max(truncated - 3, 0), - pattern_time=pattern_time, + pattern_time=pattern_time_aug, ... ) } # Date functions #### -#' Generate a regular expression matching an ISO8601 calendar year +#' Generate a regular expression matching any ISO8601 date format #' -#' @details Sign on the year (+ or -) is not supported (therefore years before -#' 0000 are not supported). Years after 9999 are not supported. +#' @details This matches YYYY-MM-DD (year-month-day), YYYY-Www-d, or YYYY-DDD +#' formats. Basic format (without dashes) is not supported. #' -#' @param allow_before_year_1583 Should years between 0 and 1582 be allowed -#' (they are only allowed in ISO 8601 with mutual agreement) +#' @param truncated Should the date be allowed to be truncated? An integer +#' indicating the highest required precision (0=day is required, 1=month or week, and +#' 2=year). A value of 3 will allow an empty string to match. +#' @inheritParams pattern_ISO8601_calendar_year +#' @inheritParams pattern_ISO8601_date_builder +#' @param ... Ignored #' @references https://en.wikipedia.org/wiki/ISO_8601 #' @family ISO8601 patterns #' @export -pattern_ISO8601_calendar_year <- function(allow_before_year_1583=FALSE) { - stopifnot(is.logical(allow_before_year_1583)) - stopifnot(!is.na(allow_before_year_1583)) - - if (allow_before_year_1583) { - "([0-9]{4})" - } else { - "(158[3-9]|159[0-9]|1[6-9][0-9]{2}|[2-9][0-9]{3})" - } +pattern_ISO8601_any_date <- function(truncated=0, allow_before_year_1583=FALSE, pattern_time="", ...) { + pattern_calendar <- + pattern_ISO8601_date_builder( + truncated=pmin(truncated, 1), + pattern_year=NULL, + pattern_middle=pattern_ISO8601_calendar_month(), + # Not confirming that the date is valid for the month + pattern_day=pattern_ISO8601_calendar_day(), + pattern_time=pattern_time + ) + pattern_week <- + pattern_ISO8601_date_builder( + truncated=pmin(truncated, 1), + pattern_year=NULL, + pattern_middle=pattern_ISO8601_week_week(), + # Not confirming that the date is valid for the month + pattern_day=pattern_ISO8601_week_day(), + pattern_time=pattern_time + ) + pattern_ordinal <- + pattern_ISO8601_date_builder( + truncated=pmin(truncated, 1), + pattern_year=NULL, + pattern_day=pattern_ISO8601_ordinal_day(), + pattern_time=pattern_time + ) + pattern_less_than_year <- + pattern_ISO8601_truncated_helper( + sprintf("(?:%s|%s|%s)", pattern_calendar, pattern_week, pattern_ordinal), + allow_truncation=truncated >= 2 + ) + pattern_year_prep <- pattern_ISO8601_calendar_year(allow_before_year_1583=allow_before_year_1583) + pattern_ISO8601_truncated_helper( + paste0(pattern_year_prep, pattern_less_than_year), + allow_truncation=truncated >= 3 + ) } #' Generate a regular expression matching an ISO8601 calendar date @@ -143,9 +262,9 @@ pattern_ISO8601_calendar_year <- function(allow_before_year_1583=FALSE) { pattern_ISO8601_calendar_date <- function(truncated=0, allow_before_year_1583=FALSE, pattern_time="", ...) { pattern_ISO8601_date_builder( truncated=truncated, - pattern_middle="(0[1-9]|1[0-2])", + pattern_middle=pattern_ISO8601_calendar_month(), # Not confirming that the date is valid for the month - pattern_day="(0[1-9]|[12][0-9]|3[01])", + pattern_day=pattern_ISO8601_calendar_day(), pattern_time=pattern_time, allow_before_year_1583=allow_before_year_1583 ) @@ -156,6 +275,9 @@ pattern_ISO8601_calendar_date <- function(truncated=0, allow_before_year_1583=FA #' @details This matches the general pattern of yyyy-Www-d (year-week of #' year-day of week). Basic format (without dashes) is not supported. #' +#' @param truncated Should the date be allowed to be truncated? An integer +#' indicating the highest required precision (0=day is required, 1=week, and +#' 2=year). A value of 3 will allow an empty string to match. #' @inheritParams pattern_ISO8601_calendar_date #' @references https://en.wikipedia.org/wiki/ISO_8601 #' @family ISO8601 patterns @@ -163,8 +285,8 @@ pattern_ISO8601_calendar_date <- function(truncated=0, allow_before_year_1583=FA pattern_ISO8601_week_date <- function(truncated=0, allow_before_year_1583=FALSE, pattern_time="", ...) { pattern_ISO8601_date_builder( truncated=truncated, - pattern_middle="W(0[1-9]|[1-4][0-9]|5[0-3])", - pattern_day="([1-7])", + pattern_middle=pattern_ISO8601_week_week(), + pattern_day=pattern_ISO8601_week_day(), pattern_time=pattern_time, allow_before_year_1583=allow_before_year_1583 ) @@ -172,6 +294,9 @@ pattern_ISO8601_week_date <- function(truncated=0, allow_before_year_1583=FALSE, #' Generate a regular expression matching an ISO8601 ordinal date #' +#' @param truncated Should the date be allowed to be truncated? An integer +#' indicating the highest required precision (0 or 1=day is required and +#' 2=year). A value of 3 will allow an empty string to match. #' @details This matches the general pattern of yyyy-ddd (year-day of year). #' Leap days are allowed, but the year is not confirmed to be a leap year. #' Basic format (without dashes) is not supported. @@ -181,9 +306,15 @@ pattern_ISO8601_week_date <- function(truncated=0, allow_before_year_1583=FALSE, #' @family ISO8601 patterns #' @export pattern_ISO8601_ordinal_date <- function(truncated=0, allow_before_year_1583=FALSE, pattern_time="", ...) { + truncated_prep <- + ifelse( + truncated == 1, + 0, + truncated + ) pattern_ISO8601_date_builder( - truncated=truncated, - pattern_day="(00[1-9]|0[1-9][0-9]|[12][0-9]{2}|3[0-5][0-9]|36[0-6])", + truncated=truncated_prep, + pattern_day=pattern_ISO8601_ordinal_day(), pattern_time=pattern_time, allow_before_year_1583=allow_before_year_1583 ) @@ -193,7 +324,8 @@ pattern_ISO8601_ordinal_date <- function(truncated=0, allow_before_year_1583=FAL #' time patterns. #' #' @param pattern_year The pattern for the ISO8601 year (ignored if -#' \code{allow_before_year_1583} is given) +#' \code{allow_before_year_1583} is given); if null, only the middle and day +#' part will be returned without a year part. #' @param pattern_middle The pattern for the ISO8601 month or week (or NULL for ordinal dates) #' @param pattern_day The pattern for the ISO8601 day #' @param pattern_time A string to add to the day for including time with date @@ -234,13 +366,59 @@ pattern_ISO8601_date_builder <- function(truncated, pattern_year, pattern_middle } else { pattern_year_prep <- pattern_ISO8601_calendar_year(allow_before_year_1583=allow_before_year_1583) } - pattern_year_aug <- - pattern_ISO8601_truncated_helper( - paste0(pattern_year_prep, pattern_middle_aug), - allow_truncation=truncated >= 3 - ) - pattern_year_aug + if (is.null(pattern_year_prep)) { + ret <- pattern_middle_aug + } else { + ret <- + pattern_ISO8601_truncated_helper( + paste0(pattern_year_prep, pattern_middle_aug), + allow_truncation=truncated >= 3 + ) + } + ret +} + +## Individual date pattern parts #### + +#' Generate a regular expression matching an ISO8601 calendar year +#' +#' @details Sign on the year (+ or -) is not supported (therefore years before +#' 0000 are not supported). Years after 9999 are not supported. +#' +#' @param allow_before_year_1583 Should years between 0 and 1582 be allowed +#' (they are only allowed in ISO 8601 with mutual agreement) +#' @references https://en.wikipedia.org/wiki/ISO_8601 +#' @family ISO8601 patterns +#' @export +pattern_ISO8601_calendar_year <- function(allow_before_year_1583=FALSE) { + stopifnot(is.logical(allow_before_year_1583)) + stopifnot(!is.na(allow_before_year_1583)) + if (allow_before_year_1583) { + "([0-9]{4})" + } else { + "(158[3-9]|159[0-9]|1[6-9][0-9]{2}|[2-9][0-9]{3})" + } +} + +pattern_ISO8601_calendar_month <- function() { + "(0[1-9]|1[0-2])" +} + +pattern_ISO8601_calendar_day <- function() { + "(0[1-9]|[12][0-9]|3[01])" +} + +pattern_ISO8601_week_week <- function() { + "W(0[1-9]|[1-4][0-9]|5[0-3])" +} + +pattern_ISO8601_week_day <- function() { + "([1-7])" +} + +pattern_ISO8601_ordinal_day <- function() { + "(00[1-9]|0[1-9][0-9]|[12][0-9]{2}|3[0-5][0-9]|36[0-6])" } # Time functions #### diff --git a/R/make_param_label.R b/R/make_param_label.R new file mode 100644 index 0000000..57f754e --- /dev/null +++ b/R/make_param_label.R @@ -0,0 +1,29 @@ +#' Generate a parameter label combining specimen type, parameter name, and units +#' +#' @param spec Specimen type (typically, "blood", "plasma", etc.) +#' @param param Parameter name (the thing that was measured) +#' @param unit Units of measure +#' @param expect_single Should a single parameter label be generated (or may it +#' be a vector)? +#' @param allow_missing_spec,allow_missing_unit Are the \code{spec} or +#' \code{unit} parameters allowed to be NA? +#' @return A character vector that is equivalent to \code{sprintf("%s %s (%s)", +#' spec, param, unit)}, but accounting for the fact that spec and unit may be +#' missing. +#' @export +make_param_label <- function(spec, param, unit, expect_single=TRUE, + allow_missing_spec=TRUE, allow_missing_unit=TRUE) { + d <- data.frame(spec=spec, param=param, unit=unit) + if (expect_single) { + d <- unique(d) + stopifnot("More than one parameter label created"=nrow(d) == 1) + } + stopifnot("spec may not be NA"=allow_missing_spec | !any(is.na(d$spec))) + stopifnot("param may not be NA"=!any(is.na(d$param))) + stopifnot("unit may not be NA"=allow_missing_unit | !any(is.na(d$unit))) + # spec may be optional + text_spec <- ifelse(is.na(d$spec), "", paste0(d$spec, " ")) + # unit may be optional + text_unit <- ifelse(is.na(d$unit), "", sprintf(" (%s)", d$unit)) + paste0(text_spec, d$param, text_unit) +} diff --git a/man/is_ISO8601_calendar_date.Rd b/man/is_ISO8601_calendar_date.Rd index 8bc327a..8104886 100644 --- a/man/is_ISO8601_calendar_date.Rd +++ b/man/is_ISO8601_calendar_date.Rd @@ -42,7 +42,9 @@ ordinal date \seealso{ Other ISO8601 String checking: \code{\link{is_ISO8601_calendar_datetime}()}, +\code{\link{is_ISO8601_ordinal_datetime}()}, \code{\link{is_ISO8601_timezone}()}, -\code{\link{is_ISO8601_time}()} +\code{\link{is_ISO8601_time}()}, +\code{\link{is_ISO8601_week_datetime}()} } \concept{ISO8601 String checking} diff --git a/man/is_ISO8601_calendar_datetime.Rd b/man/is_ISO8601_calendar_datetime.Rd index 8e58b91..f932bce 100644 --- a/man/is_ISO8601_calendar_datetime.Rd +++ b/man/is_ISO8601_calendar_datetime.Rd @@ -2,8 +2,8 @@ % Please edit documentation in R/iso8601_regexp.R \name{is_ISO8601_calendar_datetime} \alias{is_ISO8601_calendar_datetime} -\title{Determine if a string matches an ISO 8601 date/time using standard calendar -date notation} +\title{Determine if a string matches an ISO 8601 date/time using calendar date +notation} \usage{ is_ISO8601_calendar_datetime(x, ...) } @@ -20,13 +20,15 @@ string to match.} }} } \description{ -Determine if a string matches an ISO 8601 date/time using standard calendar -date notation +Determine if a string matches an ISO 8601 date/time using calendar date +notation } \seealso{ Other ISO8601 String checking: \code{\link{is_ISO8601_calendar_date}()}, +\code{\link{is_ISO8601_ordinal_datetime}()}, \code{\link{is_ISO8601_timezone}()}, -\code{\link{is_ISO8601_time}()} +\code{\link{is_ISO8601_time}()}, +\code{\link{is_ISO8601_week_datetime}()} } \concept{ISO8601 String checking} diff --git a/man/is_ISO8601_ordinal_datetime.Rd b/man/is_ISO8601_ordinal_datetime.Rd new file mode 100644 index 0000000..aa0acae --- /dev/null +++ b/man/is_ISO8601_ordinal_datetime.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/iso8601_regexp.R +\name{is_ISO8601_ordinal_datetime} +\alias{is_ISO8601_ordinal_datetime} +\title{Determine if a string matches an ISO 8601 date/time using ordinal date notation} +\usage{ +is_ISO8601_ordinal_datetime(x, ...) +} +\arguments{ +\item{x}{A vector of character strings to test} + +\item{...}{ + Arguments passed on to \code{\link[=pattern_ISO8601_ordinal_datetime]{pattern_ISO8601_ordinal_datetime}} + \describe{ + \item{\code{truncated}}{Should the date/time be allowed to be truncated? An integer +indicating the highest required precision (0=second is required, 1=minute, +2=hour, 3 or 4=day, 5=year, 6=none). A value of 6 will allow an empty +string to match.} + }} +} +\description{ +Determine if a string matches an ISO 8601 date/time using ordinal date notation +} +\seealso{ +Other ISO8601 String checking: +\code{\link{is_ISO8601_calendar_datetime}()}, +\code{\link{is_ISO8601_calendar_date}()}, +\code{\link{is_ISO8601_timezone}()}, +\code{\link{is_ISO8601_time}()}, +\code{\link{is_ISO8601_week_datetime}()} +} +\concept{ISO8601 String checking} diff --git a/man/is_ISO8601_time.Rd b/man/is_ISO8601_time.Rd index 5335db2..62e3b7a 100644 --- a/man/is_ISO8601_time.Rd +++ b/man/is_ISO8601_time.Rd @@ -39,6 +39,8 @@ Determine if a string is an ISO 8601 time Other ISO8601 String checking: \code{\link{is_ISO8601_calendar_datetime}()}, \code{\link{is_ISO8601_calendar_date}()}, -\code{\link{is_ISO8601_timezone}()} +\code{\link{is_ISO8601_ordinal_datetime}()}, +\code{\link{is_ISO8601_timezone}()}, +\code{\link{is_ISO8601_week_datetime}()} } \concept{ISO8601 String checking} diff --git a/man/is_ISO8601_timezone.Rd b/man/is_ISO8601_timezone.Rd index e464e3d..cbf9dc8 100644 --- a/man/is_ISO8601_timezone.Rd +++ b/man/is_ISO8601_timezone.Rd @@ -16,6 +16,8 @@ Determine if a string is an ISO 8601 timezone Other ISO8601 String checking: \code{\link{is_ISO8601_calendar_datetime}()}, \code{\link{is_ISO8601_calendar_date}()}, -\code{\link{is_ISO8601_time}()} +\code{\link{is_ISO8601_ordinal_datetime}()}, +\code{\link{is_ISO8601_time}()}, +\code{\link{is_ISO8601_week_datetime}()} } \concept{ISO8601 String checking} diff --git a/man/is_ISO8601_week_datetime.Rd b/man/is_ISO8601_week_datetime.Rd new file mode 100644 index 0000000..c8b82bb --- /dev/null +++ b/man/is_ISO8601_week_datetime.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/iso8601_regexp.R +\name{is_ISO8601_week_datetime} +\alias{is_ISO8601_week_datetime} +\title{Determine if a string matches an ISO 8601 date/time using week date notation} +\usage{ +is_ISO8601_week_datetime(x, ...) +} +\arguments{ +\item{x}{A vector of character strings to test} + +\item{...}{ + Arguments passed on to \code{\link[=pattern_ISO8601_week_datetime]{pattern_ISO8601_week_datetime}} + \describe{ + \item{\code{truncated}}{Should the date/time be allowed to be truncated? An integer +indicating the highest required precision (0=second is required, 1=minute, +2=hour, 3=day, 4=week, 5=year, 6=none). A value of 6 will allow an empty +string to match.} + }} +} +\description{ +Determine if a string matches an ISO 8601 date/time using week date notation +} +\seealso{ +Other ISO8601 String checking: +\code{\link{is_ISO8601_calendar_datetime}()}, +\code{\link{is_ISO8601_calendar_date}()}, +\code{\link{is_ISO8601_ordinal_datetime}()}, +\code{\link{is_ISO8601_timezone}()}, +\code{\link{is_ISO8601_time}()} +} +\concept{ISO8601 String checking} diff --git a/man/make_param_label.Rd b/man/make_param_label.Rd new file mode 100644 index 0000000..c6916bd --- /dev/null +++ b/man/make_param_label.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/make_param_label.R +\name{make_param_label} +\alias{make_param_label} +\title{Generate a parameter label combining specimen type, parameter name, and units} +\usage{ +make_param_label( + spec, + param, + unit, + expect_single = TRUE, + allow_missing_spec = TRUE, + allow_missing_unit = TRUE +) +} +\arguments{ +\item{spec}{Specimen type (typically, "blood", "plasma", etc.)} + +\item{param}{Parameter name (the thing that was measured)} + +\item{unit}{Units of measure} + +\item{expect_single}{Should a single parameter label be generated (or may it +be a vector)?} + +\item{allow_missing_spec, allow_missing_unit}{Are the \code{spec} or +\code{unit} parameters allowed to be NA?} +} +\value{ +A character vector that is equivalent to \code{sprintf("%s %s (%s)", + spec, param, unit)}, but accounting for the fact that spec and unit may be + missing. +} +\description{ +Generate a parameter label combining specimen type, parameter name, and units +} diff --git a/man/pattern_ISO8601_any_date.Rd b/man/pattern_ISO8601_any_date.Rd new file mode 100644 index 0000000..8a8c50d --- /dev/null +++ b/man/pattern_ISO8601_any_date.Rd @@ -0,0 +1,50 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/iso8601_regexp.R +\name{pattern_ISO8601_any_date} +\alias{pattern_ISO8601_any_date} +\title{Generate a regular expression matching any ISO8601 date format} +\usage{ +pattern_ISO8601_any_date( + truncated = 0, + allow_before_year_1583 = FALSE, + pattern_time = "", + ... +) +} +\arguments{ +\item{truncated}{Should the date be allowed to be truncated? An integer +indicating the highest required precision (0=day is required, 1=month or week, and +2=year). A value of 3 will allow an empty string to match.} + +\item{allow_before_year_1583}{Should years between 0 and 1582 be allowed +(they are only allowed in ISO 8601 with mutual agreement)} + +\item{pattern_time}{A string to add to the day for including time with date +(see \code{pattern_ISO8601_time()})} + +\item{...}{Ignored} +} +\description{ +Generate a regular expression matching any ISO8601 date format +} +\details{ +This matches YYYY-MM-DD (year-month-day), YYYY-Www-d, or YYYY-DDD + formats. Basic format (without dashes) is not supported. +} +\references{ +https://en.wikipedia.org/wiki/ISO_8601 +} +\seealso{ +Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_calendar_datetime}()}, +\code{\link{pattern_ISO8601_calendar_date}()}, +\code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, +\code{\link{pattern_ISO8601_ordinal_date}()}, +\code{\link{pattern_ISO8601_timezone}()}, +\code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, +\code{\link{pattern_ISO8601_week_date}()} +} +\concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_any_datetime.Rd b/man/pattern_ISO8601_any_datetime.Rd new file mode 100644 index 0000000..65163ac --- /dev/null +++ b/man/pattern_ISO8601_any_datetime.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/iso8601_regexp.R +\name{pattern_ISO8601_any_datetime} +\alias{pattern_ISO8601_any_datetime} +\title{Generate a regular expression matching any ISO8601 date format with time} +\usage{ +pattern_ISO8601_any_datetime(truncated = 0, ...) +} +\arguments{ +\item{truncated}{Should the date/time be allowed to be truncated? An integer +indicating the highest required precision (0=second is required, 1=minute, +2=hour, 3=day, 4=month or week, 5=year, 6=none). A value of 6 will allow an empty +string to match.} + +\item{...}{Passed to \code{pattern_ISO8601_any_date()} and +\code{pattern_ISO8601_time()}} +} +\description{ +Generate a regular expression matching any ISO8601 date format with time +} +\seealso{ +Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_date}()}, +\code{\link{pattern_ISO8601_calendar_datetime}()}, +\code{\link{pattern_ISO8601_calendar_date}()}, +\code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, +\code{\link{pattern_ISO8601_ordinal_date}()}, +\code{\link{pattern_ISO8601_timezone}()}, +\code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, +\code{\link{pattern_ISO8601_week_date}()} +} +\concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_calendar_date.Rd b/man/pattern_ISO8601_calendar_date.Rd index 5b683da..9884b11 100644 --- a/man/pattern_ISO8601_calendar_date.Rd +++ b/man/pattern_ISO8601_calendar_date.Rd @@ -36,11 +36,15 @@ https://en.wikipedia.org/wiki/ISO_8601 } \seealso{ Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, \code{\link{pattern_ISO8601_calendar_datetime}()}, \code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, \code{\link{pattern_ISO8601_ordinal_date}()}, \code{\link{pattern_ISO8601_timezone}()}, \code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, \code{\link{pattern_ISO8601_week_date}()} } \concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_calendar_datetime.Rd b/man/pattern_ISO8601_calendar_datetime.Rd index 723a67c..2c2e0ca 100644 --- a/man/pattern_ISO8601_calendar_datetime.Rd +++ b/man/pattern_ISO8601_calendar_datetime.Rd @@ -20,11 +20,15 @@ Generate a regular expression matching an ISO8601 calendar date with time } \seealso{ Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, \code{\link{pattern_ISO8601_calendar_date}()}, \code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, \code{\link{pattern_ISO8601_ordinal_date}()}, \code{\link{pattern_ISO8601_timezone}()}, \code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, \code{\link{pattern_ISO8601_week_date}()} } \concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_calendar_year.Rd b/man/pattern_ISO8601_calendar_year.Rd index 3bf677e..f43aa9e 100644 --- a/man/pattern_ISO8601_calendar_year.Rd +++ b/man/pattern_ISO8601_calendar_year.Rd @@ -22,11 +22,15 @@ https://en.wikipedia.org/wiki/ISO_8601 } \seealso{ Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, \code{\link{pattern_ISO8601_calendar_datetime}()}, \code{\link{pattern_ISO8601_calendar_date}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, \code{\link{pattern_ISO8601_ordinal_date}()}, \code{\link{pattern_ISO8601_timezone}()}, \code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, \code{\link{pattern_ISO8601_week_date}()} } \concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_date_builder.Rd b/man/pattern_ISO8601_date_builder.Rd index 49c6b21..ab628d0 100644 --- a/man/pattern_ISO8601_date_builder.Rd +++ b/man/pattern_ISO8601_date_builder.Rd @@ -16,7 +16,8 @@ pattern_ISO8601_date_builder( } \arguments{ \item{pattern_year}{The pattern for the ISO8601 year (ignored if -\code{allow_before_year_1583} is given)} +\code{allow_before_year_1583} is given); if null, only the middle and day +part will be returned without a year part.} \item{pattern_middle}{The pattern for the ISO8601 month or week (or NULL for ordinal dates)} diff --git a/man/pattern_ISO8601_ordinal_date.Rd b/man/pattern_ISO8601_ordinal_date.Rd index 5bf60f4..4687e8b 100644 --- a/man/pattern_ISO8601_ordinal_date.Rd +++ b/man/pattern_ISO8601_ordinal_date.Rd @@ -13,7 +13,7 @@ pattern_ISO8601_ordinal_date( } \arguments{ \item{truncated}{Should the date be allowed to be truncated? An integer -indicating the highest required precision (0=day is required, 1=month, and +indicating the highest required precision (0 or 1=day is required and 2=year). A value of 3 will allow an empty string to match.} \item{allow_before_year_1583}{Should years between 0 and 1582 be allowed @@ -37,11 +37,15 @@ https://en.wikipedia.org/wiki/ISO_8601 } \seealso{ Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, \code{\link{pattern_ISO8601_calendar_datetime}()}, \code{\link{pattern_ISO8601_calendar_date}()}, \code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, \code{\link{pattern_ISO8601_timezone}()}, \code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, \code{\link{pattern_ISO8601_week_date}()} } \concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_ordinal_datetime.Rd b/man/pattern_ISO8601_ordinal_datetime.Rd new file mode 100644 index 0000000..f8aa97a --- /dev/null +++ b/man/pattern_ISO8601_ordinal_datetime.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/iso8601_regexp.R +\name{pattern_ISO8601_ordinal_datetime} +\alias{pattern_ISO8601_ordinal_datetime} +\title{Generate a regular expression matching an ISO8601 ordinal date with time} +\usage{ +pattern_ISO8601_ordinal_datetime(truncated = 0, ...) +} +\arguments{ +\item{truncated}{Should the date/time be allowed to be truncated? An integer +indicating the highest required precision (0=second is required, 1=minute, +2=hour, 3 or 4=day, 5=year, 6=none). A value of 6 will allow an empty +string to match.} + +\item{...}{Passed to \code{pattern_ISO8601_week_date()} and +\code{pattern_ISO8601_time()}} +} +\description{ +Generate a regular expression matching an ISO8601 ordinal date with time +} +\seealso{ +Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, +\code{\link{pattern_ISO8601_calendar_datetime}()}, +\code{\link{pattern_ISO8601_calendar_date}()}, +\code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_date}()}, +\code{\link{pattern_ISO8601_timezone}()}, +\code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, +\code{\link{pattern_ISO8601_week_date}()} +} +\concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_time.Rd b/man/pattern_ISO8601_time.Rd index 0d1cffb..6dfdfd2 100644 --- a/man/pattern_ISO8601_time.Rd +++ b/man/pattern_ISO8601_time.Rd @@ -57,11 +57,15 @@ differences which could occur on different hours and at the end of any } \seealso{ Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, \code{\link{pattern_ISO8601_calendar_datetime}()}, \code{\link{pattern_ISO8601_calendar_date}()}, \code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, \code{\link{pattern_ISO8601_ordinal_date}()}, \code{\link{pattern_ISO8601_timezone}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, \code{\link{pattern_ISO8601_week_date}()} } \concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_timezone.Rd b/man/pattern_ISO8601_timezone.Rd index 1065c8b..51ce319 100644 --- a/man/pattern_ISO8601_timezone.Rd +++ b/man/pattern_ISO8601_timezone.Rd @@ -24,11 +24,15 @@ https://en.wikipedia.org/wiki/UTC_offset } \seealso{ Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, \code{\link{pattern_ISO8601_calendar_datetime}()}, \code{\link{pattern_ISO8601_calendar_date}()}, \code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, \code{\link{pattern_ISO8601_ordinal_date}()}, \code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()}, \code{\link{pattern_ISO8601_week_date}()} } \concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_week_date.Rd b/man/pattern_ISO8601_week_date.Rd index 8564426..70abe99 100644 --- a/man/pattern_ISO8601_week_date.Rd +++ b/man/pattern_ISO8601_week_date.Rd @@ -13,7 +13,7 @@ pattern_ISO8601_week_date( } \arguments{ \item{truncated}{Should the date be allowed to be truncated? An integer -indicating the highest required precision (0=day is required, 1=month, and +indicating the highest required precision (0=day is required, 1=week, and 2=year). A value of 3 will allow an empty string to match.} \item{allow_before_year_1583}{Should years between 0 and 1582 be allowed @@ -36,11 +36,15 @@ https://en.wikipedia.org/wiki/ISO_8601 } \seealso{ Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, \code{\link{pattern_ISO8601_calendar_datetime}()}, \code{\link{pattern_ISO8601_calendar_date}()}, \code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, \code{\link{pattern_ISO8601_ordinal_date}()}, \code{\link{pattern_ISO8601_timezone}()}, -\code{\link{pattern_ISO8601_time}()} +\code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_datetime}()} } \concept{ISO8601 patterns} diff --git a/man/pattern_ISO8601_week_datetime.Rd b/man/pattern_ISO8601_week_datetime.Rd new file mode 100644 index 0000000..2b120a9 --- /dev/null +++ b/man/pattern_ISO8601_week_datetime.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/iso8601_regexp.R +\name{pattern_ISO8601_week_datetime} +\alias{pattern_ISO8601_week_datetime} +\title{Generate a regular expression matching an ISO8601 week date with time} +\usage{ +pattern_ISO8601_week_datetime(truncated = 0, ...) +} +\arguments{ +\item{truncated}{Should the date/time be allowed to be truncated? An integer +indicating the highest required precision (0=second is required, 1=minute, +2=hour, 3=day, 4=week, 5=year, 6=none). A value of 6 will allow an empty +string to match.} + +\item{...}{Passed to \code{pattern_ISO8601_week_date()} and +\code{pattern_ISO8601_time()}} +} +\description{ +Generate a regular expression matching an ISO8601 week date with time +} +\seealso{ +Other ISO8601 patterns: +\code{\link{pattern_ISO8601_any_datetime}()}, +\code{\link{pattern_ISO8601_any_date}()}, +\code{\link{pattern_ISO8601_calendar_datetime}()}, +\code{\link{pattern_ISO8601_calendar_date}()}, +\code{\link{pattern_ISO8601_calendar_year}()}, +\code{\link{pattern_ISO8601_ordinal_datetime}()}, +\code{\link{pattern_ISO8601_ordinal_date}()}, +\code{\link{pattern_ISO8601_timezone}()}, +\code{\link{pattern_ISO8601_time}()}, +\code{\link{pattern_ISO8601_week_date}()} +} +\concept{ISO8601 patterns} diff --git a/tests/testthat/test-iso8601_regexp.R b/tests/testthat/test-iso8601_regexp.R index 7fc396d..3ee4584 100644 --- a/tests/testthat/test-iso8601_regexp.R +++ b/tests/testthat/test-iso8601_regexp.R @@ -1,7 +1,5 @@ # pattern_ISO8601_calendar_datetime #### -## pattern_ISO8601_calendar_datetime expected errors #### - test_that("pattern_ISO8601_calendar_datetime", { datetimes_to_test <- c( @@ -237,6 +235,8 @@ test_that("pattern_ISO8601_calendar_datetime", { ) }) +## pattern_ISO8601_calendar_datetime expected errors #### + test_that("pattern_ISO8601_calendar_datetime expected errors", { expect_error(pattern_ISO8601_calendar_datetime(truncated="A")) expect_error(pattern_ISO8601_calendar_datetime(truncated=1:2)) @@ -244,6 +244,12 @@ test_that("pattern_ISO8601_calendar_datetime expected errors", { expect_error(pattern_ISO8601_calendar_datetime(truncated=7)) }) +# pattern_ISO8601_any_date #### + +# test_that("pattern_ISO8601_any_date", { +# +# }) + # pattern_ISO8601_calendar_date #### test_that("pattern_ISO8601_calendar_date", { @@ -464,7 +470,7 @@ test_that("pattern_ISO8601_ordinal_date", { all( is_ISO8601_ordinal_date( c( - valid_ordinal_date_yd, valid_ordinal_date_y + valid_ordinal_date_yd ), truncated=1 ) @@ -474,7 +480,7 @@ test_that("pattern_ISO8601_ordinal_date", { any(is_ISO8601_ordinal_date( c( invalid_ordinal_date_yd, invalid_ordinal_date_y, - valid_ordinal_date_none + valid_ordinal_date_y, valid_ordinal_date_none ), truncated=1 )) diff --git a/tests/testthat/test-make_param_label.R b/tests/testthat/test-make_param_label.R new file mode 100644 index 0000000..d1acaf9 --- /dev/null +++ b/tests/testthat/test-make_param_label.R @@ -0,0 +1,54 @@ +test_that("make_param_label errors", { + expect_error( + make_param_label(spec=NA, param=NA, unit=NA, allow_missing_spec=FALSE), + regexp="spec may not be NA" + ) + expect_error( + make_param_label(spec="A", param=NA, unit=NA), + regexp="param may not be NA" + ) + expect_error( + make_param_label(spec="A", param="A", unit=NA, allow_missing_unit=FALSE), + regexp="unit may not be NA" + ) + + expect_error( + make_param_label(spec=NA, param=NA, unit=NA), + regexp="param may not be NA" + ) + expect_error( + make_param_label(spec="A", param=NA, unit=NA), + regexp="param may not be NA" + ) + expect_error( + make_param_label(spec=c("A", "B"), param="A", unit=NA), + regexp="More than one parameter label created" + ) +}) + +test_that("make_param_label", { + expect_equal( + make_param_label(spec=NA, param="A", unit=NA), + "A" + ) + expect_equal( + make_param_label(spec="B", param="A", unit=NA), + "B A" + ) + expect_equal( + make_param_label(spec=NA, param="A", unit="C"), + "A (C)" + ) + expect_equal( + make_param_label(spec="B", param="A", unit="C"), + "B A (C)" + ) + expect_equal( + make_param_label(spec=c("B", "D"), param="A", unit="C", expect_single=FALSE), + c("B A (C)", "D A (C)") + ) + expect_equal( + make_param_label(spec=c("B", "D"), param="A", unit="C", expect_single=FALSE), + c("B A (C)", "D A (C)") + ) +})