Check that x is a character vector with unique, syntactically valid names
that do not suggest they were adjusted or automatically created.
Value
TRUE or FALSE, indicating if x is a character vector that consists of
unique, syntactically valid names that do not consist of only dots or of
two dots followed by a number, and do not suggest they were adjusted or
automatically created.
Details
Duplicated or syntactically invalid names are not allowed by
all_names() because R functions are not guaranteed to handle such names
correctly. For example, not all operations on data frames
will preserve duplicated column names, and operations involving syntactically
invalid names might, by definition, give undocumented results.
Syntactically valid names only consist of letters, numbers,
dots and underscores; start with a letter, or with a dot not followed by a
number; and are not reserved words such as for or NA. The
definition of letter depends on the current locale, such that
names containing accented letters like é and letters that are only present
in some alphabets like the German Eszett are allowed by all_names() if
these characters are encoded in the used locale (see the Programming notes
on a stricter check that would not allow these characters letters).
Names that consist of only dots, or consist of two dots followed by a number,
are not allowed by all_names() (nor by vctrs::vec_as_names()) even though
they are not adjusted by make.names(): they are reserved words.
Suspicious names are not allowed by all_names(). A suspicious name is a
syntactically valid name that contains a pattern suggesting it originally was
syntactically invalid or not unique and has been adjusted into a
unique, syntactically valid, name. Such adjustments usually
occur silently, for
example when data is read into R, such that it should not be assumed
that column names after reading data into R are the same as the column names
before reading data into R. The identification of suspicious names is partly
based on the assumption that names originally did not contain dots, see the
first item in the list below.
all_names() tries to recognise adjustments made by make.names(),
which is used by data.frame(), utils::read.csv(), and
data.table::fread(x, header = TRUE, check.names = TRUE); and adjustments
made by vctrs::vec_as_names(x, repair = "universal"), which is used
throughout the tidyverse:
adjustments to replace invalid characters (i.e., characters that are not a letter, number, dot or underscore):
make.names()andvctrs::vec_as_names(x, repair = "universal")replace such characters with a dotTheir identification is based on the assumption that names originally did not contain dots, which is good practice preventing names containing a dot from being confused with methods used on classed objects, even though that practice is not strictly followed in base R, e.g., in the function name
data.frame().
adjustments to make duplicated names unique:
make.names(x, unique = TRUE)appends a dot followed by a numbervctrs::vec_as_names(x, repair = "universal")appends three dots followed by a number.
make.names()does not adjust the first instance of a duplicate, whereasvctrs::vec_as_names()does adjust it:make.names(c("a", "b", "c", "b", "a"), unique = TRUE)returnsc("a", "b", "c", "b.1", "a.1"), whereasvctrs::vec_as_names(c("a", "b", "c", "b", "a"), repair = "universal")returnsc("a...1", "b...2", "c", "b...4", "a...5"), with...<number>indicating the position in the vectoradjustments to make reserved words valid:
make.names()appends a dotvctrs::vec_as_names(x, repair = "universal")prepends a dot
adjustments to make names that did not start with a letter, nor with a dot not followed by a number, syntactically valid:
make.names()prependsXvctrs::vec_as_names(x, repair = "universal")prepends one or more dots
adjustments to name unnamed columns:
as.data.frame()andread.csv(..., header = FALSE)use patternV1,V2,V3read.csv(..., header = TRUE)uses patternX,X.1,X.2data.frame()creates names in a complex way, see the SectionValuein data.frame for some details.all_names()only detects names created for unnamed columns if the names were syntactically invalid and therefore gotXput in front of them.
It is not checked if a complete sequence of suspicious names is present, e.g.,
V3will be flagged as suspicious even ifV1andV2are absent.
Names containing underscores (_) are by default allowed by all_names()
because names containing underscores are not syntactically invalid. However,
setting allow_underscores to FALSE to not allow such names is useful
to check that names do not contain underscores, for example if several names
will be concatenated to create an ID-tag, separating the names by underscores.
Programming notes
The patterns used to identify suspicious names are created using regular expressions with the following elements:
require a pattern to start at the beginning of a string (
^) or reach the end of a string ($)specify characters that should be present: a dot (
\\.or, iffixedisTRUE,.), an underscore (_), any digit ([0-9]), digits one to nine ([1-9]), charactersVorX)indicate presence: present zero or more times (
*); present one or more times (+)
Multiple patterns can be combined using |, the normal operator indicating
logical OR.
A conservative check for names that are syntactically valid on
all locales would
only allow
digits, unaccented letters from the
basic Latin alphabet,
dots and underscores.
Implementations of such a conservative check should use the literal string
[0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz] instead of
shorthands like [:alnum:] or [0-9A-Za-z] that also depend on the locale,
see section Extended Regular Expressions in regex. See Encoding,
locales, validUTF8(), and the Wikipedia articles about
ASCII and
UTF-8 for background on encodings and
character sets. Furthermore, see iconv() on conversions between encodings;
package stringi that provides
facilities to process character strings;
tools::showNonASCII() to show the non-ASCII bytes;
and janitor::make_clean_names() to transliterate non-ASCII characters.
See also
Section Details of make.names(), section Names and Identifiers of
Quotes(), and the R FAQ about valid names
on the syntactical validity of names.
names() to get or set object names; janitor::make_clean_names() to adjust
names; rlang::names_inform_repair() for a method to report name changes if
old and new names are provided.
Other collections of checks on type and length:
all_characters(),
is_logical(),
is_natural(),
is_number(),
is_path(),
is_zerolength()
Examples
all_names(x = c("a", "b2a")) # TRUE
#> [1] TRUE
all_names(x = c("a", "b2a", "a")) # FALSE: duplicated name
#> Warning: Names are duplicated: 'a'.
#> Use 'make.names(c("a", "b2a", "a"), unique = TRUE)' to create unique, syntactically valid names!
#> [1] FALSE
invalid_names <- c("a", "ab#cd", "", "for", "..", "..23")
# Syntactically invalid names: the character '#' makes names invalid,
# '""' is an empty name, 'for', '..', and '..23' are reserved words.
all_names(x = invalid_names) # FALSE
#> Warning: Names are syntactically invalid: 'ab#cd', 'for', '""' (i.e., an empty string); and consist of only dots, which is a reserved word: '..'; and consist of two dots followed by digits, which is a reserved word: '..23'.
#> Use 'invalid_names <- make.names(invalid_names, unique = TRUE)' to create unique, syntactically valid names
#> (it does not adjust names that consist of only dots, or two dots followed by digits)!
#> [1] FALSE
# Names that have been made valid are suspicious
# (but make.names() does not adjust ".." or "..23"):
all_names(x = make.names(invalid_names)) # FALSE
#> Warning: Names consist of only dots, which is a reserved word: '..'; and consist of two dots followed by digits, which is a reserved word: '..23'; and are suspicious: 'ab.cd', 'X', 'for.'
#> [1] FALSE
# FALSE: suspicious names
all_names(x = c("e.2", "a.1b", ".TRUE", "..22c", "a...2",
"V3", "X.2", "X0...11", "X0.3", "X3"))
#> Warning: Names are suspicious: 'e.2', 'a.1b', '.TRUE', '..22c', 'a...2', 'V3', 'X.2', 'X0...11', 'X0.3', 'X3'
#> [1] FALSE
all_names(x = "abc_def", allow_underscores = FALSE) # FALSE: underscores
#> Warning: Names contain underscores (which are not allowed if 'allow_underscores' is FALSE):
#> 'abc_def'.
#> Use '"abc_def" <- make.names("abc_def", unique = TRUE, allow_ = FALSE)' to create unique,
#> syntactically valid names without underscores!
#> [1] FALSE
all_names(x = "abc_def", allow_underscores = TRUE) # TRUE
#> [1] TRUE
# pass names() or colnames() used on an object
# without (column) names to all_names():
all_names(x = names(1:3)) # FALSE
#> Warning: 'x' (names(1:3)) is NULL: did you use names() or colnames() on an object without
#> (column) names and passed the result to all_names()?
#> [1] FALSE
all_names(13) # FALSE: 'x' is not a character vector
#> Warning: Input to 'x' is not a character vector: 13
#> [1] FALSE