1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rust で Tab stop を実装(タブをスペースに変換)

Posted at

はじめに

Markdown などのテキスト処理を行う際にタブをスペースに変換する必要があることがあります。

この変換を実装する上で、タブストップ(Tab stop)の概念が重要になります。

本記事では、タブをスペースに変換する機能を Rust で実装する方法を紹介します。

タブ は、テキスト内に挿入される特殊な空白文字で、通常はタブキーを押すことで生成されます。具体的には、Unicode 文字 U+0009 に対応し、エスケープシーケンスでは \t と表現されます。

タブストップ は、テキスト内でタブ文字が次に移動する位置を示します。例えば、タブストップが 4 文字ごとに設定されている場合、行の先頭から 4 文字ごとに仮想的な基準線が設定されます。

    | ◯ ◯ ◯ ◯ | ◯ ◯ ◯ ◯ | ◯ ◯ ◯ ◯ | ◯ ◯ ◯ ◯ | ◯ ◯ ◯ ◯ |

Tab と Tab stop の違い -Qiita

実装

テキスト内のタブを指定されたタブサイズに基づいてスペースに変換する関数を実装します。

文字列を前から処理していき、タブに遭遇すると次のタブステップまでをタブサイズに基づいてスペースで埋めます。

以下のように挙動(\thello\t! ->     hello   !)することを想定しています。

tab_size = 4 の場合
  \t  h  e  l   l  o \t  !                              <- 入力値
 | ◯  ◯  ◯  ◯ | ◯  ◯  ◯  ◯ | ◯  ◯  ◯  ◯ | ◯  ◯  ◯  ◯ |
   ␣  ␣  ␣  ␣   h  e  l  l  \t  !                       <- 1 つ目の Tab を変換
   ␣  ␣  ␣  ␣   h  e  l  l   o  ␣  ␣  ␣   !             <- 出力値(2 つ目の Tab を変換)

\t はタブ、 はスペースを表しています。

タブストップの位置までの文字数を計算する関数

まず、次のタブストップの位置までの文字数を計算する関数を実装します。

fn next_tab_stop(position: usize, tab_size: usize) -> usize {
    tab_size - (position % tab_size)
}

この関数は、現在の文字位置(position)とタブサイズ(tab_size)を入力として受け取り、次のタブストップの位置までの文字数を計算します。

タブをスペースに変換する関数

次に、文字列内のタブをスペースに変換する関数を実装します。この関数は、タブに遭遇すると次のタブストップまでのスペースを挿入します。

fn replace_tabs_with_spaces(input: &str, tab_size: usize) -> String {
    let mut result = String::new();
    let mut position = 0;

    for c in input.chars() {
        if c == '\t' {
            let next_stop = next_tab_stop(position, tab_size);
            result.push_str(&" ".repeat(next_stop));
            position += next_stop;
        } else {
            if c == '\n' {
                position = 0;
            } else {
                position += 1;
            }
            result.push(c);
        }
    }

    result
}
※ 改行コードは \n のみを前提としています。

\r\r\n も対象とする場合は、改行コードを統一してから replace_tabs_with_spaces 関数を使用するか、replace_tabs_with_spaces 関数内で改行コードを統一する必要があります。

fn normalize_newlines(text: &str) -> String {
    text.replace("\r\n", "\n").replace('\r', "\n")
}

fn replace_tabs_with_spaces(input: &str, tab_size: usize) -> String {
    // ...

-    for c in input.chars() {
+    for c in normalize_newlines(input).chars() {

    // ...
}

main 関数での実行

最後に、main 関数でこれらの関数を使ってタブをスペースに変換します。

fn main() {
    let tab_size = 4;
    let input = "Hello\tWorld!\nThis\tis\ta\ttest.";

    let output = replace_tabs_with_spaces(input, tab_size);
    println!("Original:\n{}", input);
    println!("Modified:\n{}", output);
}
実行結果
Original:
Hello	World!
This	is	a	test.
Modified:
Hello   World!
This    is  a   test.

まとめ

本記事では、タブ文字をスペースに変換する Rust 関数の実装方法を紹介しました。

具体的には、タブストップの位置までの文字数を計算する関数と、それを利用して文字列内のタブをスペースに変換する関数を作成しました。

このような機能は Markdown や他のテキスト処理において重要になります。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?