Introduction to stringr

stringr には、大きく分けて4つの関数ファミリーがあります。

  1. 文字操作:これらの関数により、文字ベクトル内の文字列の個々の文字を操作することができます。

  2. 空白ツール:空白を追加、削除、操作するためのツールです。

  3. ロケール依存の操作:操作はロケールによって異なります。

  4. パターンマッチ機能。パターン記述の4つのエンジンを認識します。最も一般的なのは正規表現ですが、その他に3つのツールがあります。

個々の文字の取得と設定

文字列の長さは str_length() で得ることができます。

str_length("abc")
#> [1] 3

これは、Rの基本関数 nchar() と同等になりました。以前は、nchar()の問題、例えば nchar(NA) に対して 2 を返してしまうという問題を回避するために必要でした。これは R 3.3.0 の時点で修正されたので、もはやそれほど重要ではありません。

個々の文字にアクセスするには、 str_sub() を使います。これは3つの引数を取ります: 文字ベクトル、 start 位置と end 位置です。前者は左から数えて正の整数か、後者は右から数えて負の整数になります。位置は文字列を含んでおり、文字列よりも長い場合は静かに切り捨てられます。

x <- c("abcdef", "ghifjk")

# The 3rd letter
str_sub(x, 3, 3)
#> [1] "c" "i"
# The 2nd to 2nd-to-last character
str_sub(x, 2, -2)
#> [1] "bcde" "hifj"

また、文字列を修正するために str_sub() を使用することができます。

str_sub(x, 3, 3) <- "X"
x
#> [1] "abXdef" "ghXfjk"

個々の文字列を複製するには、str_dup() を使用することができます。

str_dup(x, c(2, 3))
#> [1] "abXdefabXdef"       "ghXfjkghXfjkghXfjk"

空白文字

3つの関数が空白を追加、削除、修正します。

  1. str_pad() は、文字列の左側、右側、または両側に余分な空白を追加して、一定の長さになるようにパディングします。

    x <- c("abc", "defghi")
    str_pad(x, 10) # default pads on left
    #> [1] "       abc" "    defghi"
    str_pad(x, 10, "both")
    #> [1] "   abc    " "  defghi  "

    (引数 pad を使えば、他の文字で埋めることができます)。

    str_pad() は決して文字列を短くすることはありません。

    str_pad(x, 4)
    #> [1] " abc"   "defghi"

    ですから、すべての文字列が同じ長さになるようにしたい場合(printメソッドでよく役に立ちます)、 str_pad()str_trunc() を組み合わせてください。

    x <- c("Short", "This is a long string")
    
    x %>% 
      str_trunc(10) %>% 
      str_pad(10, "right")
    #> [1] "Short     " "This is..."
  2. str_pad()の反対は str_trim() で、これは先頭と末尾の空白を削除します。

    x <- c("  a   ", "b   ",  "   c")
    str_trim(x)
    #> [1] "a" "b" "c"
    str_trim(x, "left")
    #> [1] "a   " "b   " "c"
  3. str_wrap() を使うと、段落のテキストを折り返すために既存の空白を修正し、各行の長さができるだけ同じになるようにすることができます。

    jabberwocky <- str_c(
      "`Twas brillig, and the slithy toves ",
      "did gyre and gimble in the wabe: ",
      "All mimsy were the borogoves, ",
      "and the mome raths outgrabe. "
    )
    cat(str_wrap(jabberwocky, width = 40))
    #> `Twas brillig, and the slithy toves did
    #> gyre and gimble in the wabe: All mimsy
    #> were the borogoves, and the mome raths
    #> outgrabe.

ロケールの影響

いくつかの stringr 関数は、ロケールに依存します:世界の異なる地域で異なる動作をします。これらの関数は大文字と小文字の変換を行う関数です。

x <- "I like horses."
str_to_upper(x)
#> [1] "I LIKE HORSES."
str_to_title(x)
#> [1] "I Like Horses."
str_to_lower(x)
#> [1] "i like horses."
# Turkish has two sorts of i: with and without the dot
str_to_lower(x, "tr")
#> [1] "ı like horses."

文字列の順序と並べ替え。

x <- c("y", "i", "k")
str_order(x)
#> [1] 2 3 1
str_sort(x)
#> [1] "i" "k" "y"
# In Lithuanian, y comes between i and k
str_sort(x, locale = "lt")
#> [1] "i" "y" "k"

ロケールのデフォルトは常に英語であり、システム間で同じ動作をするようにします。ロケールには、常に 2 文字の ISO-639-1 言語コード (英語なら “en” 、中国語なら “zh”) と、オプションで ISO-3166 国コード (en_UK" や “en_US” など) を指定することができます。利用可能なロケールの完全なリストは stringi::stri_locale_list() を実行することで見ることができます。

パターンマッチ

stringr 関数の大半はパターンを使って動作します。これらの関数は、実行するタスクとマッチするパターンの種類によってパラメータ化されています。

タスク

各パターンマッチング関数の最初の2つの引数は同じで、処理する文字列の文字ベクトルとマッチする1つの pattern です。stringr は文字列の detect, locate, extract, match, replace, split に対してパターンマッチング関数を提供します。ここでは、いくつかの文字列と、(米国の)電話番号にマッチするように設計された正規表現を用いて、これらの機能がどのように働くかを説明します。

strings <- c(
  "apple", 
  "219 733 8965", 
  "329-293-8753", 
  "Work: 579-499-7527; Home: 543.355.3679"
)
phone <- "([2-9][0-9]{2})[- .]([0-9]{3})[- .]([0-9]{4})"

エンジン

stringr がパターンを記述するために使用できる主なエンジンは4つあります。

固定マッチ

fixed(x)x で指定されたバイト列と正確にマッチするだけです。これは非常に限定された「パターン」ですが、この制限によってマッチングをより高速に行うことができます。英語以外のデータで fixed() を使用することに注意してください。同じ文字を表現するのに複数の方法があることが多いので、問題があります。例えば、“á” を定義する場合、一文字として定義する方法と、“a” にアクセントを加えたものとして定義する方法の二通りがあります。

a1 <- "\u00e1"
a2 <- "a\u0301"
c(a1, a2)
#> [1] "á" "á"
a1 == a2
#> [1] FALSE

これらは同じようにレンダリングされますが、定義が異なるため、 fixed() はマッチを見つけることができません。代わりに、以下に説明する coll() を使用すると、人間の文字比較ルールを尊重することができます。

str_detect(a1, fixed(a2))
#> [1] FALSE
str_detect(a1, coll(a2))
#> [1] TRUE

照合順序の検索

coll(x) は人間の言語による collation ルールを使って x にマッチするものを探します。大文字小文字を区別しないマッチングを行いたい場合には特に重要です。照合順序のルールは世界中で異なるので、 locale パラメータを指定する必要があります。

i <- c("I", "İ", "i", "ı")
i
#> [1] "I"  "İ" "i"  "ı"
str_subset(i, coll("i", ignore_case = TRUE))
#> [1] "I" "i"
str_subset(i, coll("i", ignore_case = TRUE, locale = "tr"))
#> [1] "İ" "i"

coll() の欠点は速度です。どの文字が同じであるかを認識するルールが複雑なため、 coll()regex()fixed() に比べて相対的に遅くなります。なお、 fixed()regex() の両方が ignore_case 引数を持つ場合は、 coll() よりもずっと単純な比較を行います。

境界

boundary() は、文字、行、文、単語の間の境界をマッチさせます。これは str_split() と一緒に使うと便利ですが、すべてのパターンマッチング関数と一緒に使うことができます。

x <- "This is a sentence."
str_split(x, boundary("word"))
#> [[1]]
#> [1] "This"     "is"       "a"        "sentence"
str_count(x, boundary("word"))
#> [1] 4
str_extract_all(x, boundary("word"))
#> [[1]]
#> [1] "This"     "is"       "a"        "sentence"

慣例により、""boundary("character") として扱われます。

str_split(x, "")
#> [[1]]
#>  [1] "T" "h" "i" "s" " " "i" "s" " " "a" " " "s" "e" "n" "t" "e" "n" "c" "e" "."
str_count(x, "")
#> [1] 19