ラベル 正規表現 の投稿を表示しています。 すべての投稿を表示
ラベル 正規表現 の投稿を表示しています。 すべての投稿を表示

2011年8月5日金曜日

Excel, LibreOffice, SQL におけるワイルドカード (*) の意味

1. Excel でワイルドカード

Excel で文字データを入力した。入力中、不明なデータについては、半角で

?

とした。後になって、不明なデータを検索しようと `?’ を検索。しかし、上手くヒットしない。ただし、全角の

?

で検索すると、半角の ? がヒットした。

なぜなら、Excel では、半角の `?’ が 任意の一文字を表すため。また、全角の `?’ は、文字通りクエッションマークとして認識され、デフォルトでは半角と全角を区別しないことにより、半角の `?’ も検索対象となるため。

「*」と「?」を検索する:Excel即効テクニック によると、

Excelでデータを検索するときに文字列の一部が分からなくても、ワイルドカードと呼ばれる特別な記号「*」と「?」を使って検索できるのはご存知の通り。「*」は任意の文字列を表し「?」は任意の1文字を表す。…

「*」と「?」を検索文字として指定するときは「~*」「~?」のように「~」を付けて入力すればよい

正規表現 – Wikipedia の書き方とは違うので気をつける必要がある。

 

2. LibreOffice で正規表現による検索

これに対して、LibreOffice では、正規表現で検索できる。

Writer/Using Wildcards in Text Searches/ja - LibreOffice Help によると、

  • 編集 → 検索と置換を選択します。
  • ダイアログを展開するには、詳細オプションをクリックします。
  • 正規表現チェックボックスを選択します。
  • 素直に書けるので、検索するときに間違えることはない。

  • 任意の 1 文字を表すワイルドカードは、ピリオド記号 (.) です。
  • 直前の文字の任意回数の繰り返し (ゼロ回を含む) を示すワイルドカードは、アスタリスク記号です。
  • LibreOffice の方がシンプルで好きだなぁ。

     

    3. SQL との比較

    ちなみに、SQL では、任意の一文字を表すのに `_’ を用いる。

    SQLの基礎「SELECT」文を覚えよう によると、

    (4) LIKE条件
    文字の検索条件を指定します。ここで、%と_(アンダースコア)は特殊な意味が割り当てられており、%は「任意の文字数の任意の文字」、_は「1文字の任意の文字」を表します。

    Access は `?’, `_’ が任意の一文字を表す。

    あいまいな条件抽出 - LIKE演算子 : SQL入門講座 によると、

    アスタリスク (*)
    パーセント(%)

    0文字以上の任意の文字列を表す。

    疑問符(?)
    アンダスコア(_)

    任意の一文字を表す。

    普段から使ってないと、混乱する。 (+_+)

    2009年12月15日火曜日

    Google Sites における HTML の不要なタグや属性を一括で削除 - 正規表現を使って

    1. フォントの装飾だけ取り除きたい

    Google Sites は、Google ドキュメントのように文字に色を付けたり、サイズを変更することが簡単にできる。

    SnapCrab_NoName_2013-1-8_0-13-30_No-00しかし、お手軽さが災いし、文字の装飾を繰り返すと、元の状態に戻したくても修正するのが面倒になる。(+_+)

    メニューより、

    「書式 > 書式をクリア」

    により、文字の装飾を削除することはできる。しかし、「見出し」や「リスト」を適用した段落設定も消えてしまう。

     

    2. エディタを使い正規表現で一括削除

    Google Site では、ツールバーの右端にある

    • 「HTML ソースを編集」ボタン

    を選択し、フォントの装飾情報を直接削除することができる。しかし、一々手作業で削除するのは気が遠くなる。そこで、正規表現で文字列を置換できるエディタを使い、フォント情報を削除することにした。

    SnapCrab_NoName_2013-1-8_0-15-34_No-00ここではエディタとして Aptana を利用する。

     

    a. Firefox のアドオン It’s All Text! で HTML を編集

    SnapCrab_NoName_2013-1-8_0-18-11_No-00Firefox のアドオン It's All Text! を使うと、ブラウザのテキストエリアをエディタで編集できる。

    It's All Text! をインストールし、エディタを Aptana に設定した。

    SnapCrab_NoName_2013-1-8_0-19-1_No-00次に、Google Sites で、メニューボタンの右端にある HTML を編集するボタンをクリック。

    It’s All Text! がインストールされていると、右端に「編集」ボタンが表示される。これを右クリックし、

    「.html」として編集

    を選択する。

    091215-021.png

     

    b. 正規表現で置換

    Aptana で編集対象の HTML が開かれたら、メニューより

    • Edit > Find/Replace

    を選択する (Ctrl + F)。

    091215-019.pngダイアログの Options で Regular expressions にチェックを入れる。 

    例えば、 HTML における style 属性と Font タグを削除したいとする。

    style 属性を正規表現で指定するには、

    style=(.+?)"

    Font タグを指定するには、

    <font(.+?)>|</font>

    よって、Find: フィールドには

    style=(.+?)"|<font(.+?)>|</font>

    と指定すれば良い。Replace With: フィールドは空にしておく。

    後は、Replace/Find ボタンで確認しながら除去する。

    ついでに、メニューより Edit > Format を適用しておくと、見やすくなる。

    Aptana で編集したファイルを保存し、Google Site に戻り、HTML が更新されたのを確認したら、更新ボタンを押す。

    2009年10月8日木曜日

    正規表現の空文字列

    プログラム中の正規表現を使っている関数で、意図しない動作をする箇所があった。

    例えば、次のような関数 replace 。引数で渡された文字列を元に正規表現を作り、マッチする文字列を置き換える。

    var replace = function(sentence, word, repl){
        var r = new RegExp(word, "gi");
        return sentence.replace(r, repl);
    };
    
    console.log(replace("hogepiyohoge", "hoge", "--"));

    結果は、

    --piyo--

    これは問題ない。しかし、ある条件で次のような文字列が渡っているのに気がつかなかった。

    console.log(replace("hogepiyo", "|", "--"));

    結果を見て、あれ?と。(@_@;)

    --h--o--g--e--p--i--y--o--

     

    意図せず関数を呼出したとは言え、正規表現で /|/ って何を表わすんだろ?

    strfriend で /a|b/ を表示させると、

    091008-004

    次に /|/ を表示させると、

    091008-005

    空文字 または 空文字 ということだったか。 (+_+) つまり、// と変わらないということかぁ。

    正規表現の基本 によると、

    空文字列(くうもじれつ)とは、何も文字が含まれないの文字列の事です。
    数字には0という、何も無いことを示す数字がありますが、それの文字版と思えば良いでしょう。
    文字が何も無いのに文字列というのも変な話ですが、長さが0の文字列と考えれば、多少分かりやすいかもしれません。

     

    JavaScript で正規表現を使って確認しておく。

    "hoge".replace(/og/, "---");   

    結果は "h---e"

    "hoge".replace(/|/, "---")

    結果は ”---hoge”

    "hoge".replace(/|/g, "---")

    では、結果は “---h---o---g---e---“

    正規表現でマッチした文字列を後方参照

    1. マッチした文字列を表す $&

    どうも何度も忘れるなぁ~ (@_@;)

    正規表現は基本的なことしか覚えていない。細かいことはその都度確認。それにしても何でこうも忘れるんだろう。

    マッチした文字列を表わす、

    $&

    $ と & が横に並んでいると、一見ごちゃごちゃして見にくい。

     

    2. 後方参照

    後方参照を表わす $1, $2, … はまず忘れない。

    マッチした文字の前の部分は $` で、マッチした文字の後方部分は $’ は意外にも覚えている。

    なぜなら、以下を読んだから。

    覚え方: `は文字列の前に置かれる

    覚え方: 'は文字列の後ろに置かれる

    (組み込み変数 - Rubyリファレンスマニュアル より)

     

    3. 覚え方?

    上記より、3 点セットで

    `&’

    というイメージを頭に描くのだけれど、真ん中だけなぜか思い出せなくなる。 (+_+)

    `○’

    ○は何だっけ?と。

    うーーーーーん、なんで & なんだろ?

     

    4. 写経

    JavaScript で練習。

    "hogepiyofuga".replace(/piyo/, "--$&--");     // "hoge--hoge--fuga"
    "hogepiyofuga".replace(/piyo/, "--$`--");     // "hoge--piyo--fuga"
    "hogepiyofuga".replace(/piyo/, "--$'--");     // "hoge--fuga--fuga"

    2009年9月26日土曜日

    JavaScript で正規表現

    JavaScript で正規表現を使いたい。

    JavaScript: The Good Parts (p75) によると、

    4873113911JavaScript において正規表現が利用できるメソッドは、regexp.exec, regexp.test, string.match, string.replace, string.search, string.split である。

    RegExp, string ごとにメソッドを整理。

    RegExp

    string

  • exec
  • test
  • match
  • replace
  • search
  • split
  •  

    String.match

    String オブジェクトの match メソッドを試す。

    "abcdef123".match(/(b.).*(\d{3})/)

    結果は、

    ["bcdef123", "bc", "123"]

    match – MDC によると、

    正規表現が g フラグを含んでいない場合、regexp.exec(string) と同じ結果を返します。

    exec メソッドは、

    特定の文字列でのマッチのための検索を実行します。結果の配列、あるいは、null が返ります。

    結果として返される配列の中身は、

    [1], ...[n]
    括弧で囲まれた部分文字列のマッチ。括弧で囲まれた部分文字列の数に制限はありません。

    (同上より)

     

    例

    例えば、

    Google の検索において、検索した文字列を取得したい。

    Google で検索した後のURL を見ると、クエリ文字列のパラメータ q の値が検索文字列のようなので、

    decodeURIComponent(location.search.match(/q=(.*?)&/)[1]);

     

    location.search と decodeURIComponent

    上記 location.search は「JavaScript で URL からフラグメント以外を取得」を参照。

    decodeURIComponent メソッドは、

    エンコードされた URI の要素内のエスケープシーケンスをそれぞれが表す文字に置き換えます。

     

    最左最短一致

    正規表現における

    .*?

    はの意味は、

    量指定子の後ろに?を付けると、最短でマッチさせます。この最左最短一致を「なまけもの(non-greedy)マッチ」とも言います

    (量と位置を指定する via Yahoo! Pipes で、RSS を出力してないサイトをRSS化する より)

    2009年1月14日水曜日

    Meadow (Emacs) のライブラリをポータブルに - Dropbox へ配置

    1. php-mode のインストールと設定

    Emacs で PHP を編集するために、php-mode を利用する。

    SourceForge.net: PHP mode for Emacs からダウンロードして解凍。

    設定方法は、Installation - PHP Mode Manual を参考にして、

    1. Emacs Lisp のライブラリに php-mode.el を置く。
    2. .emacs に以下を追記。
    (load "php-mode")
    (add-to-list 'auto-mode-alist
         '("\\.php[34]?\\'\\|\\.phtml\\'" . php-mode))

    PHP ファイルを Emacs で開いた場合、表示が次のように変わる。

    g2413

     

    拡張子を追加

    Drupal のソースファイルの拡張子は .php ではなく、.module, .inc 。この拡張のファイルを開いたときも、php-mode を利用したい。

    Installation - PHP Mode Manual  を参考にして、

    (add-to-list 'auto-mode-alist '("\\.module\\'" . php-mode))
    (add-to-list 'auto-mode-alist '("\\.inc\\'" . php-mode))

     

    2. Dropbox に Emacs のライブラリを置く

    現在、Emacs のライブラリはローカルに配置している。どの場所にいても、同じライブラリを使いたいので、ライブラリを Dropbox フォルダに置くことにした。

    My Documents\My Dropbox

    に eslips フォルダを作成。上記の php-mode.el を置いた。

    初期設定ファイル (~/.emacs) に、ライブラリのフォルダを認識させるために、以下を記述。

    (add-to-list 'load-path "~/My Documents/My Dropbox/elisp")

     

    3. その他

    設定に関する関数や変数を調べたい場合、

    正規表現におけるバックスラッシュについては、

    2009年1月13日火曜日

    Emacs Lisp の正規表現

    1. バックスラッシュだらけの正規表現

    Emacs で .php ファイルを開いたとき、php-mode になるように設定した。

    .emacs には、以下の文を追加してある。

    (add-to-list 'auto-mode-alist
         '("\\.php[34]?\\'\\|\\.phtml\\'" . php-mode))

    正規表現を表した文字列を抜き出す。

    \\.php[34]?\\'\\|\\.phtml\\'

    パッと見、バックスラッシュが多すぎて、何が書いてあるのか分からない。 (+_+)

     

    2. バックスラッシュを使った正規表現の意味

    Emacs Lisp プログラミング: 正規表現の探索 によると、

    Emacsでは、最初のバックスラッシュはそれに続くバックスラッシュをクオートし、 2番目のバックスラッシュは、それに続く括弧や縦棒が特別な文字であることを表す。

    よって、上記の正規表現は、以下のようになる。

    \.php[34]?\'\|\.phtml\'

    上記には 3 種類のバックスラッシュを使った表現が使われている。

    • \.
    • \|
    • \'

    マニュアルを参照。

    \.

    `.’ は正規表現において、特別な意味を持つ。

    33.2.1 正規表現の構文 によると、

    `.' (ピリオド)

    特別な文字であり、改行以外の任意の1文字に一致する。連結を使って`a.b'のような正規表現を作れる。

    文字であるピリオドとして使いたい場合、バックスラッシュでピリオドをエスケープする。

     

    \|

    正規表現において、`X|Y’ はX, Y の和集合を表す。

    33.2.1 正規表現の構文 によると、

    多くの場合、任意の文字を伴う`\'はその文字だけに一致します。しかし、いくつか例外があって、 `\'で始まる2文字列が特別な意味を持つ場合があります。

    `\|'
    選択肢を指定する。 `\|'をあいだに伴った2つの正規表現aとbは、 aかbのいずれかに一致する文字列に一致する正規表現となる。

     

    \’

    33.2.1 正規表現の構文 によると、

    つぎの正規表現は空の文字列に一致します。つまりこれらは文字を使用しませんが、これらが一致するかどうか文脈に依存します。

    `\''

    空の文字列に一致するが、一致対象であるバッファや文字列の末尾に限る。

    「バッファ」とは、GNU Emacsマニュアル: 複数のバッファの使い方 によると、

    Emacs内で編集しているテキストはバッファ(buffer)と呼ばれるオブジェクトの中に存在します。ファイルを訪問するたびに、ファイルのテキストを保持するバッファを作ります。

    では、空文字とは何だろう?

    33.2.1 正規表現の構文によると、

    `[ ... ]'
    `['で始まり`]'で終る文字選択を表す。もっとも単純な場合は、この2つの中括弧のあいだにある文字の1つ1つがこの文字選択に一致する。

    したがって、`[ad]'は、`a'1文字か`d'1文字のどちらにも一致する。 `[ad]*'は、`a'と`d'だけから成る(空の文字列を含む)任意の文字列に一致する。このことから、`c[ad]*r'は、 `cr'、`car'、`cdr'、`caddaar'などに一致することがわかる。

    `^'
    空の文字列に一致する特別な文字であり、一致を取る対象のテキストの行頭のみに一致する。それ以外では、一致に失敗する。したがって、`^foo'は、行頭にある`foo'に一致する。

    バッファのかわりに文字列と一致を取るときには、 `^'は文字列の先頭や改行文字`\n'のうしろに一致する。

    `$'
    `^'と同様だが行末のみに一致する。したがって、`x+$'は、行末にある1文字以上の`x'から成る文字列に一致する。

    バッファのかわりに文字列と一致を取るときには、 `$'は文字列の末尾や改行文字`\n'のまえに一致する。

    正規表現において、^, $ は、行頭、行末を表す。Emacs のドキュメントによると、 ^, $ は、行頭、行末の「空の文字列」と一致するとの説明。

    よって、\’ は、行末を表す $ に類似した表現で、対象がバッファとなっていると見なせば良い。

     

    3. re-builder で正規表現の確認

    正規表現を確認するためには、re-builder を使う。

    48.3.1 正規表現の作成・確認 ― re-builder によると、

    簡単な検索ならともかく,複雑な正規表現となると,これで本当にうまく検索できるのか不安になりませんか?

    そんな正規表現を実際に試すことができるものが, re-builder です.

    標準で付属してますので,M-x re-builderとするだけで使うことができます.

    re-builder の入力により、“\\’” でバッファの末尾に一致。 “\\`” でバッファの先頭に一致。

    “\^” が行における先頭を表し、”\$” が行末を表すのと同じ。

     

    4. 正規表現をリテラルに戻す

    Emacs には、次の関数が定義されている。

    GNU Emacs Lisp Reference Manual - 正規表現のマッチングを行なう関数

    Function: regexp-quote string

    この関数は、 string に正確にマッチし他のものにマッチしない正規表現のストリングを返します。

    先ほどの正規表現に対して、この関数を適用してみる。

    (message (regexp-quote "\.php[34]?\'\|\.phtml\'"))
    "\\.php\\[34]\\?'|\\.phtml'"

    元の表現には、戻らなかった。

    Emacs Lisp によると、

    もし、バックスラッシュが多すぎてよく分らないのなら、正規表現を評価した後の形について考えればよい。文字列を評価する簡単な方法としては、 *scratch* バッファに insert することが挙げられる。

    (insert "\\\\\\*")
    → \\\*

    "\\\\\\*" という謎の正規表現も、'\\\*' となる。こればバックスラッシュの後にアスタリスクが続く文字列に合致する。バックスラッシュもアスタリスクもメタ文字なので、バックスラッシュが前についてzいるだけのことだ。

    初心者は insert による方法を思い付かず、逆にリテラルを正規表現に直そうとする傾向にあるようだ。そして、regexp-quote という関数を発見してぬか喜びをする。この関数の役割は、リテラルを正規表現へ直すことではないから、忘れる方がいい。

    元の表現に insert 関数を適用してみる。

    (insert "\\.php[34]?\\'\\|\\.phtml\\'")

    結果は、

    \.php[34]?\'\|\.phtml\'

     

    5. その他

    正規表現については特によく忘れる… (+_+)

    Python における正規表現もややこしかった。

     

    関連記事

    関連サイト

    2008年10月26日日曜日

    Haskell で文字列の分割と結合

    文字列をリストへ分割

    改行で区切るなら、

    lines :: String -> [String]

    空白で区切るなら、

    words :: String -> [String]

    特定の文字列で区切るなら正規表現を使って、( Text.Regex )

    splitRegex :: Regex -> String -> [String]

    import Text.Regex
    
    main = do
      print $ lines "hoge\npiyo\nfuga"
      print $ words "hoge piyo fuga"
    
      print $ splitRegex (mkRegex ",") "hoge,piyo,fuga"
      print $ splitRegex (mkRegex "--") "hoge--piyo--fuga"

     

    リストを文字列へ戻す

    lines, words の接頭辞として `un’ をつける。

    文字列でくっつけたい場合は、intercalate 。(cf. Haskell でリストの要素を join - List.Data の intersperse, intercalate)

    import Data.List
    
    css = ["hoge","piyo","fuga"]
    
    main = do
      putStrLn $ unlines css
      putStrLn $ unwords css
    
      putStrLn $ intercalate "—" css

    結果は、

    hoge
    piyo
    fuga
    
    hoge piyo fuga
    hoge--piyo--fuga

    単に文字列のリストをくっつけて、文字列にしたいだけなら concat 。文字列のリストは、文字のリストのリストであるため。

     

    日本語

    日本語を扱うときは、「Haskell で日本語表示 - utf8-string を利用して」 を参照。

     

    関連記事

    2008年10月24日金曜日

    Haskell で正規表現 (2) =~ , Python・Ruby と比較しながら

    以前試したように Haskell において正規表現を使いたい場合は、Text.Regex モジュールを利用する。(cf. Haskell で正規表現)

    流れとしては、

    1. 「正規表現型の値」を生成 : mkRegex
    2. (1) を利用して一致する部分があるか確かめる : matchRegex 
    import Text.Regex
    main = do 
        print $ matchRegex (mkRegex "(piyo)") "123hogepiyofuga"
        print $ matchRegexAll (mkRegex "(piyo)") "123hogepiyofuga"

    結果は、

    Just ["piyo"]
    Just ("123hoge","piyo","fuga",["piyo"])

    ただし、matchRegex において Just で包んで返される値は、 mkRegex の正規表現で subexpression として指定 したもの。

     

    Python と比較

    Python でも同様の手順を踏む。

    1. compile
    2. match または search (cf. 4.2.2 マッチング vs 検索)
    import re
    print re.compile("piyo").match("123hogepiyofuga")
    print re.compile("piyo").search("123hogepiyofuga")

    結果、

    None
    <_sre.SRE_Match object at 0x025F6598>

     

    search と match の違い

    4.2.3 モジュール コンテンツ によると、

    search(pattern, string[, flags])

    string全体を走査して、…

    match(pattern, string[, flags])

    もし string の先頭で0 個以上の文字が正規表現 pattern と マッチすれば、…

    Haskell の matchRegex は search に相当するということかな。

     

    compile なし

    上記は正規表現を使い回さないのであれば、compile せずに、

    print re.match("piyo", "123hogepiyofuga")
    print re.search("piyo","123hogepiyofuga")

     

    matchRegexAll のように

    Haskell の matchRegexAll と同じものを取得するには、4.2.5 MatchObject オブジェクト を使い、

    str = "123hogepiyofuga"
    m = re.search("(piyo)",str)
    print str[:m.start()], m.group(1), str[m.end():], m.groups()

    結果は、

    123hoge piyo fuga ('piyo',)

     

    Ruby と比較

    Ruby で正規表現と言えばすぐに /正規表現/=~ “文字列” を思い出す。(cf. Regexp - Rubyリファレンスマニュアル) そういう書き方ができるから、テキスト処理をするとき Ruby は扱いやすいなぁ~と思った。組み込み変数 は忘れてしまうけれど。 ^^;

    p /(piyo)/ =~ "123hogepiyofuga"
    p $`, $1, $', $~.to_a

    結果、

    7
    "123hoge"
    "piyo"
    "fuga"
    ["piyo", "piyo"]

    せっかくなので、上記の組み込み変数だけでも覚えておこう。

    `~’

    Python でも =~ が使えるといいのに…。 (+_+)

     

    Haskell でも =~

    Text.Regex.Posix.Wrap

    前回、A Haskell regular expression tutorial を読むのを見逃してた。(via Cookbook - HaskellWiki) Haskell でも Ruby と同じように =~ が使えるようだ。

    定義されている場所は、Text.Regex の一つ下の階層に Text.Regex.Posix があり、そのまた下の Text.Regex.Posix.Wrap。どういうモジュールかと思って見てみると、

    WrapPosix.hsc exports a wrapped version of the ffi imports.

    FFIとは - はてなキーワード 

    ある言語から他言語で作成したライブラリを呼び出すインターフェイスで、ラッパーを作らずに直接呼び出す事が特徴である。

    …と言われても、何に対してどうなのか具体的によくわからなかった。 ^^;

     

    =~ の型

    それはさておき、 =~ を見ると、

    (=~) :: (RegexMaker Regex CompOption ExecOption source, RegexContext Regex source1 target) => source1 -> source -> target

    うわっ!(@_@;) この型クラスの制約はどうやって読めばいいのだろうか? QQQ

    A Haskell regular expression tutorial によると、とりあえずはシンプルに考えておけと。

    this function is polymorphic in both its arguments and its return type; … Here’s a simplified type signature, to give you the idea.

      (=~) :: string -> pattern -> result
    

    (I’ve left out the constraints on these type variables. …

    なるほど。しかし、引数だけではなく、返り値の型まで多相とは…?

     

    使い方

    とりあえず、上記にならって使い方を試してみる。

    import Text.Regex
    import Text.Regex.Posix
    main = do 
      print $ ("123hogepiyofuga" =~ "(piyo)" :: Bool)       # True

    最後の :: Bool と型を指定するのがポイント。

    最初にマッチした文字列を返すには、

      print $ ("123hogepiyofuga" =~ "(piyo)" :: String)     # "piyo"

    マッチした全ての文字列をリストにして返すには、

      print $ ("123hogepiyofuga" =~ "(piyo)" :: [String])    # ["piyo"]

    マッチした部分よりも前、マッチした文字列、マッチした文字列の後ろを返したい場合は、

      print $ ("123hogepiyofuga" =~ "(piyo)" :: (String,String,String))   # ("123hoge","piyo","fuga")

    上記に加えて、先ほどのように部分式にマッチした文字列をリストにしたものも加えたい場合は、

      print $ ("123hogepiyofuga" =~ "(piyo)" :: (String,String,String,[String]))  # ("123hoge","piyo","fuga",["piyo"])

    マッチした文字列の位置とその長さを得たい場合は、Text.Regex.Base をインポートしておいた上で、

      print $ ("123hogepiyofuga" =~ "(piyo)" :: (MatchOffset,MatchLength))  # (7,4)

    2008年10月6日月曜日

    Python におけるバックスラッシュ (\) の扱いと、row stirng と正規表現における注意点

    1. エスケープシーケンスにより表現する文字

    Python で、バックスラッシュを文字列として出力したい。

    print r'\'

    しかし、これではシンタックスエラーとなる。

    他の言語と同様に、特定の文字の前にバックスラッシュ (\) を付けると、特殊な文字や機能を表わす。

    例えば、「改行」を文字列の中に含むには、\n を記述する。

    print 'hoge\npiyo'

    文字列を出力させた結果は、

    hoge
    piyo

    `\n’ は改行を表わし、これをエスケープシーケンスと言う。

    エスケープシーケンス - Wikipedia とは、

    コンピュータシステムにおいて、通常の文字列では表せない特殊な文字や機能を、規定された特別な文字の並びにより表したもの。狭義には、エスケープコード (0x1B, ESC) に始まる一連のバイト列のことをいう。

    エスケープシーケンスとして、他に以下のような種類がある。

    注意することは、

    \’ \”

    と書いた場合、文字列リテラルを表現するときの、引用符をエスケープしていることになる。よって、

    print '\'
    print "\"

    は、エスケープシーケンスと解釈され、引用符が閉じられていないことになる。文字列リテラルとしては不正。

     

    2. バックスラッシュを出力するには

    バックスラッシュ (\) はエスケープシーケンスを表現するために用いられる。そのため、バックスラッシュを表現するには、

    \\

    と書く。

    print '\\'     #=> \
    print '\\\\'   #=> \\

     

     

    2. row string を使ったバックスラッシュの表現

    文字列リテラルの前に `r’ をつけると row string になる。

    2.4.1 文字列リテラル によると、

    接頭文字 "r" または "R" がある場合、バックスラッシュの後にくる文字はそのまま文字列中に入り、バックスラッシュは全て文字列中に残されます。

    例えば、

    print r'hoge\npiyo'   #=> hoge\npiyo

    このような結果になるのは、

    1. バックスラッシュの後にくる文字 `n’ は、そのまま文字列に入り
    2. `n’ の前のバックスラッシュは文字列中に残される。

    Python におけるエスケープシーケンスは、

    標準の C とは違い、認識されなかったエスケープシーケンスはそのまま文字列中に残されます。(同上より)

    例えば、

    print '\c'    #=> \c

    だから、先ほど `n’ の前の文字列中に残されたバックスラッシュ (\) は、そのまま表示される。

     

    バックスラッシュの場合

    バックスラッシュを出力するために、row string を利用する。

    print r'\\'     #=> \\
    print r'\\\\'   #=> \\\\

    このような結果になるのは、

    1. バックスラッシュの後ろにくる文字 `\’ はそのまま文字列に入り
    2. の前のバックスラッシュは文字列中に残される。

    `r’ を文字列の前につけることにより、エスケープシーケンスの解釈を変化させる。

    最初に書いたように、以下の記述はエラーとなる。

    print r'\'

    なぜなら、そもそも \’ は一重引用符をエスケープしているため、全体として文字列リテラルとなっていないため。これにより、文字列リテラルの前にあることで意味を持つ `r’ が意味を持たなくなってしまっている。

    同様に、以下の記述は、

    print r'\\\'

    最初の \\ が Python における \ と解釈されるが、最後の \’ によって文字列リテラルとならずエラーとなる。同じく接頭辞 `r’ は意味を持たない。

    これは文字列リテラルの定義を見ると、明らかになる。

    stringprefix の中にある `r’ は、shortstring, longstring という引用符に囲まれた文字列の前にあることによって意味をなす。よって、引用符で囲まれた文字列がないと意味を成さない。

    上記の動作を考えると、

    1. 最初に \\ が \ と解釈され、
    2. 次に \’ \” のエスケープシーケンスがチェックされ、
    3. 文字列リテラルかがどうか確認された後に `r’ としての解釈が行われる

    ということだろうか。

     

    3. 正規表現

    正規表現において、バックスラッシュ (\) は * や . を、特別な記号として解釈されないために用いられる。

    バックスラッシュを表すには `\\’ と書く必要がある。

    そのため、Python の文字列の中で

    「正規表現のバックスラッシュ」

    を表すには、

    1. 「正規表現」においてバックスラッシュ \ を、バックスラッシュでエスケープする。 \\
    2. 「Python」 では \ を表現するのに \\ を用いる。そのため、正規表現 \\ を文字列リテラルとして用いるには、 \\\\  とする。

    つまり、「正規表現 → Python におけるリテラル表現」というように、二段階考える必要がある。

    例えば、以下のコードは、

    import re
    print re.sub('\\\\', 'Hoge', '\\\\')   #=> HogeHoge

    正規表現で言うなら、

    文字列 \\ に対して、正規表現で \ に相当するものを Hoge で置き換える

    という意味になる。(sub メソッド の第 1 引数は、正規表現のパターンを表現している。)

     

    row string

    正規表現を表す文字列に対して、row string を用いてみる。

    print re.sub(r'\\', 'Hoge', '\\\\')   #=> HogeHoge

    接頭辞 r により、 \ の解釈が変化し、\\ を表現していることになる。

    これは正規表現において \ をエスケープしていることになるので、\ そのものが置換の対象となる。対象の文字列は \\\\ なので、Python の文字列リテラルにおいて \\ を表わす。よって、\\ に対して \ を Hoge で置き換えるという意味になる。

    同様に考えれば、

    print re.sub(r'\\', 'Hoge', r'\\\\')    #=> HogeHogeHogeHoge
    print re.sub('\\\\', 'Hoge', r'\\\\')   #=> HogeHogeHogeHoge

    正規表現のレベルで書けば、どちらも

    「文字列 \\\\ に対してパターン \\ で Hoge に置き換える」

    ということになる。つまり人間から見れば、\ を Hoge で置き換えるということ。

    あ~、ややこしい~ (@_@;)

    2008年7月10日木曜日

    Haskell で正規表現 (1)

    1. Text.Regex

    Haskell で正規表現を使うには、Text.Regex を利用する。

    Text.Regex.Posix における正規表現は、POSIX regular expression.

    Uses the POSIX regular expression interface in Text.Regex.Posix

    POSIX regular expression については、

    POSIX とは Wikipedia によると、

    POSIX(ポジックス、Portable Operating System Interface)とは、異なる実装のUNIX OSを始めとする各種OSに共通のAPIを定め、移植性の高いアプリケーションソフトウェアの開発を容易にすることを目的としてIEEEが策定したアプリケーションインタフェイス規格。POSIXの「X」はUNIX互換OSにXがつく名前が多いことからつけられたもの。

    ふつうのHaskellプログラミング には、正規表現を使う方法が説明されていない。その代わりに、特定の文字列が含まれるか検査する関数に対して、次のように解説している。、

    この関数では行lineに文字列patternが含まれているかを判定したいのですが、意外にも、そのものズバリの関数はHaskellのPreludeモジュールにはありません。(p93)

    Haskell では、文字列に対するマッチングを、リスト処理の観点から行うのが普通なのだろうか (?_?)

     

    2. matchRegex

    mkRegex によって Regex 型の値を生成し、それが対象の文字列にマッチするか matchRegex で調べる。
    import Text.Regex
    main = do print $ matchRegex (mkRegex "hoge") "hogepiyofuga"
              print $ matchRegex (mkRegex "piga") "hogepiyofuga"
    結果は、Just [] と Nothing 。 Nothing の方はいいのだけれど Just [] というのは何だろう (?_?)

    Returns: Just strs if the match succeeded (and strs is the list of subexpression matches),

    と書かれているがよくわからなかった。 ^^; list of subexpression が空なのはなぜ? → 以下の 追記(2008.10.24) を参照。

    ちなみに、 mkRegex のところの正規表現を ( ) で囲むと、Just [“hoge”] というように返されるようだ。

     

    subexpression

    追記(2008.10.24) : subexpression というのは「部分式」と訳される。

    Rx - Posix Basic Regular Expressions によると、

    部分式とは、\( と \)とに囲まれた正規表現である。

    Regular expression - Wikipedia, the free encyclopedia にも同様に書かれている。

    \( \)
    Defines a marked subexpression. The string matched within the parentheses can be recalled later (see the next entry, \n). A marked subexpression is also called a block or capturing group.

    つまり、上記で引用した通り、matchRegex 関数において Just で包んで返されるものは subexpression にマッチしたものということ。

     

    3. matchRegexAll

    matchRegexAll を使うと、

    「マッチする前、マッチしたもの、マッチした後、 subexpression matches 」

    を取得できる。やはりこの subexpression が謎。 (+_+)  → 上記の 追記(2008.10.24) を参照。
    case 式を使って場合分けをするコードを書いてみると、

    import Text.Regex
    main = do putStrLn $ case matchRegexAll (mkRegex "piyo") "123hogepiyofuga" of
                           Just x -> show x
                           otherwise -> "Nothing"

    結果は ("123hoge","piyo","fuga",[]) のようにタプルで返される。 例えば、マッチした後の結果だけが必要であれば、 case 式の中で Just (_, _, x, _) –> x のようにマッチを行う。Just の中身についてはドキュメントを見ると、

      Just ( everything before match,
             portion matched,
             everything after the match,
             subexpression matches )

     

    後で読む

    うーん、難しくてわからない。 (@_@;) がんばって勉強しよ~。

     

    関連記事

    2008年5月29日木曜日

    Python, Ruby で簡単なテキスト処理 (1) - 特定の単語が含む行を抽出する

    1. 特定の単語が含む行を抽出したい

    ちょっとしたテキストを加工しようと思う場合、 Ruby を使うことが多い。

    例えば、テキストの中から特定の単語が含まれた列を抽出し、何らかの処理をしたいとする。

    対象となるテキストは次のもの。

    hoge
    piyo
    ほげほげ
    ぴよぴよ
    ほげ\nぴよ
    10,20,30
    100,200,300
      hoge  hoge
      piyo  piyo

     

    2. Ruby の場合

    ここから、「ほげ」を含む列を抽出する場合、次のように書く。

    DATA.each do |line|
    	puts line if line =~ /ほげ/
    end
    
    __END__
    ここに対象のテキストを貼り付ける。

    Ruby では、

    __END__

    以降にあるテキストを読み込んで処理できるので、軽く試したいときに便利。

     

    3. Python の場合

    まずは、Ruby の __END__ と同じような機能が Python にもないかと探した。

    スクリプト言語の比較::__END__ によると、

    ない。ただし各モジュール、クラス、関数の最初に記述するドキュメント文字列中に、利用例としてテストケースを記述し、自動テストを実施するdoctestという仕組みがある。

    パタッ(o_ _)o~†

    スクリプト系の言語なら、同じような記述ができると思ったのが甘かった。 ^^; どうするのが一番楽ができるのだろうか?

    とりあえず、変数に対象の文字列を代入して、処理するという形にしてみる。

    lines = ur"""ここに対象のテキストを貼り付ける
    """
    
    import re
    
    for line in lines.split('\n'):
        if re.search(ur"ほげ", line):
            print line

    文字列の前の ur は、2.4.1 String literals によると、

    String literals may optionally be prefixed with a letter "r" or "R"; such strings are called raw strings and use different rules for interpreting backslash escape sequences. A prefix of "u" or "U" makes the string a Unicode string.

    Unicode であり、raw string であることを示している。

    r を付けたのは、対象のテキストの中に、 \n が含まれるため。 r を付けないと、対象のテキスト中にある \n が「改行」と解釈されてしまう。

    それにしても、正規表現を使うだけで、モジュールをインポートしないといけないのは面倒。Ruby のように

     /正規表現/

    のように書けないのだろうか... (@_@;)

     

    覚え方

    ur と re.search を使うことを、記憶しておくには、どうするか?

    「裏リサーチ」

    と覚えておくことにしよう。

    追記(2008/6/3): Windows xp 上で、Python 2.5 を利用している。上記の lines 変数に代入した対象のテキストに「タブや空白」があると、 print 文でなぜか余分な空白行が出力されてしまう。そこで、改行コードを LF (UNIX) にしたら、普通に表示された。 なぜだろう (?_?)

    それから、コード上で文字列を分割している split() だと、タブでも分割されてしまうので、 split('\n') に変更した。

    「Python, Ruby で簡単なテキスト処理 (2) - 表からのデータの抽出」につづく…

     

    4. 参考