Проверьте, является ли значение символа допустимым именем объекта R - PullRequest
4 голосов
/ 06 декабря 2011

Несколько месяцев назад я спросил что-то похожее , но я использовал JavaScript, чтобы проверить, является ли предоставленная строка "допустимым" именем объекта R.Теперь я хотел бы добиться того же, не используя ничего, кроме R. Я полагаю, что есть очень хороший способ сделать это с некоторой аккуратной (не очень) эзотерической функцией R, поэтому регулярные выражения кажутся мне последней линией защиты,Есть идеи?

О, да, использование бэк-тиков и прочего считается мошенничеством.=)

Ответы [ 2 ]

10 голосов
/ 06 декабря 2011

Отредактировано 2013-1-9 для исправления регулярного выражения. Предыдущее регулярное выражение, взятое со страницы 456 «Программного обеспечения для анализа данных» Джона Чамберса, было (немного) неполным.(Хэтли Уикхем)


Здесь есть несколько проблем.Простое регулярное выражение может использоваться для идентификации всех синтаксически допустимых имен - но некоторые из этих имен (например, if и while) являются «зарезервированными» и не могут быть назначены.

  • Идентификация синтаксически допустимых имен:

?make.names объясняет, что синтаксически допустимое имя:

[...] состоит из букв, цифр и точки или символов подчеркивания и начинается с буквы или точки, за которой не следует число.Такие имена, как «.2way» недопустимы [...]

Вот соответствующее регулярное выражение:

  "^([[:alpha:]]|[.][._[:alpha:]])[._[:alnum:]]*$"
  • Идентификация незарезервированные синтаксически допустимые имена

Для идентификации незарезервированных имен можно воспользоваться базовой функцией make.names(), которая создает синтаксически допустимые имена из произвольных строк символов.

    isValidAndUnreserved <- function(string) {
        make.names(string) == string
    }

    isValidAndUnreserved(".jjj")
    # [1] TRUE
    isValidAndUnreserved(" jjj")
    # [1] FALSE
  • Собираем все вместе

    isValidName <- function(string) {
        grepl("^([[:alpha:]]|[.][._[:alpha:]])[._[:alnum:]]*$", string)
    }
    
    isValidAndUnreservedName <- function(string) {
        make.names(string) == string
    }
    
    testValidity <- function(string) {
        valid <- isValidName(string)
        unreserved <- isValidAndUnreservedName(string)
        reserved <- (valid & ! unreserved)
        list("Valid"=valid,
             "Unreserved"=unreserved,
             "Reserved"=reserved)
    }
    
    testNames <- c("mean", ".j_j", "...", "if", "while", "TRUE", "NULL",
                   "_jj", "  j", ".2way") 
    t(sapply(testNames, testValidity))
    
          Valid Unreserved Reserved
    mean  TRUE  TRUE       FALSE   
    .j_j  TRUE  TRUE       FALSE   
    ...   TRUE  TRUE       FALSE   
    if    TRUE  FALSE      TRUE    
    while TRUE  FALSE      TRUE    
    TRUE  TRUE  FALSE      TRUE    
    NULL  TRUE  FALSE      TRUE    
    _jj   FALSE FALSE      FALSE   
      j   FALSE FALSE      FALSE   # Note: these tests are for "  j", not "j"
    .2way FALSE FALSE      FALSE  
    

Подробнее об этих проблемах см. theТема r-devel , на которую ссылается @Hadley в комментариях ниже.

5 голосов
/ 06 декабря 2011

Как предполагает Джош, make.names, вероятно, лучшее решение для этого.Он не только обрабатывает странные знаки препинания, но и помечает зарезервированные слова:

make.names(".x")   # ".x"
make.names("_x")   # "X_x"
make.names("if")   # " if."
make.names("function")  # "function."
...