🔣

Reactで全角ひらがなをキーで押したとき、TextFieldに半角カナを入力する実装を作ってみた

2024/05/27に公開

背景

  • 全角ひらがな入力をキーボードでした際、入力欄に半角カナ入力として出力できないかをいろいろ調べた
  • 「IMEで全角ひらがなを選択しているとき、半角カナを選択して入力などできないか」と調べたところ、「ReactやNextだと直接IME制御はできない」とのこと
  • 「入力しているタイミングで全角ひらがなから半角カナに変換する実装をすればいいのでは」といろいろ格闘してみた

結果できたコード

import React, { useState } from 'react';

const ZenkanaToHankanaConverter = () => {
  //入力、出力のための状態を定義
  const [input, setInput] = useState('');
  const [output, setOutput] = useState('');

  //ひらがなからカタカナに変換する関数を定義
  const hiraganaToKatakana = (str) => {
    // ひらがなのUnicode範囲を表す正規表現
    return str.replace(/[\u3041-\u3096]/g, function (match) {
      //match: replaceメソッドで見つかったひらがなの文字列を示す
      //+ 0×60: Unicode値にこの値(16新数で言うところの96に該当)を加えることで、
      // 対応するカタカナのUnicode値を得ることができる
      let chr = match.charCodeAt(0) + 0x60;
      // fromCharCode: 指定したUnicodeの値を表す文字列を返すJSの組み込み関数
      return String.fromCharCode(chr);
    });
  };

  // 全角から半角に変換する関数を定義
  //マッピングを1文字1文字する必要がある(スマートではない)
  const fullToHalf = (str) => {
    let kanaMap = {
      ガ: 'ガ',
      ギ: 'ギ',
      グ: 'グ',
      ゲ: 'ゲ',
      ゴ: 'ゴ',
      ザ: 'ザ',
      ジ: 'ジ',
      ズ: 'ズ',
      ゼ: 'ゼ',
      ゾ: 'ゾ',
      ダ: 'ダ',
      ヂ: 'ヂ',
      ヅ: 'ヅ',
      デ: 'デ',
      ド: 'ド',
      バ: 'バ',
      ビ: 'ビ',
      ブ: 'ブ',
      ベ: 'ベ',
      ボ: 'ボ',
      パ: 'パ',
      ピ: 'ピ',
      プ: 'プ',
      ペ: 'ペ',
      ポ: 'ポ',
      ヴ: 'ヴ',
      ヷ: 'ヷ',
      ヺ: 'ヺ',
      ア: 'ア',
      イ: 'イ',
      ウ: 'ウ',
      エ: 'エ',
      オ: 'オ',
      カ: 'カ',
      キ: 'キ',
      ク: 'ク',
      ケ: 'ケ',
      コ: 'コ',
      サ: 'サ',
      シ: 'シ',
      ス: 'ス',
      セ: 'セ',
      ソ: 'ソ',
      タ: 'タ',
      チ: 'チ',
      ツ: 'ツ',
      テ: 'テ',
      ト: 'ト',
      ナ: 'ナ',
      ニ: 'ニ',
      ヌ: 'ヌ',
      ネ: 'ネ',
      ノ: 'ノ',
      ハ: 'ハ',
      ヒ: 'ヒ',
      フ: 'フ',
      ヘ: 'ヘ',
      ホ: 'ホ',
      マ: 'マ',
      ミ: 'ミ',
      ム: 'ム',
      メ: 'メ',
      モ: 'モ',
      ヤ: 'ヤ',
      ユ: 'ユ',
      ヨ: 'ヨ',
      ラ: 'ラ',
      リ: 'リ',
      ル: 'ル',
      レ: 'レ',
      ロ: 'ロ',
      ワ: 'ワ',
      ヲ: 'ヲ',
      ン: 'ン',
      ァ: 'ァ',
      ィ: 'ィ',
      ゥ: 'ゥ',
      ェ: 'ェ',
      ォ: 'ォ',
      ッ: 'ッ',
      ャ: 'ャ',
      ュ: 'ュ',
      ョ: 'ョ',
      '。': '。',
      '、': '、',
      ー: 'ー',
      '「': '「',
      '」': '」',
      '・': '・',
   '*': '*',
    };
    var reg = new RegExp('(' + Object.keys(kanaMap).join('|') + ')', 'g');
    return str
      .replace(reg, function (match) {
        return kanaMap[match];
      })
      .replace(/゛/g, '゙')
      .replace(/゜/g, '゚');
  };

  //   const handleInputChange = (event) => {
  //     setInput(event.target.value);
  //     var katakana = hiraganaToKatakana(event.target.value);
  //     setOutput(fullToHalf(katakana));
  //   };
  //   入力が変更されたときのイベントハンドラ
  const handleInputChange = (event) => {
    var inputVal = event.target.value;
    var katakana = hiraganaToKatakana(inputVal); //ひらがなをカタカナに変換
    var hankana = fullToHalf(katakana); //全角カタカナを半角カタカナに変換
    setInput(hankana); // 入力フィールドを返還後の値で更新
    setOutput(hankana); // 出力状態も入力フィールドと同様、変換後の値で更新
  };

  return (
    <div>
      <TextField
        type="text"
        value={input}
        onChange={handleInputChange}
        //下記のIMEモードをオフにする設定は、
        //ブラウザによってはサポートされていないので多分意味がない
        sx={{ imeMode: 'inactive' }}
      />
      <p>{output}</p>
    </div>
  );
};

export default ZenkanaToHankanaConverter;

【ボツ案】半角カナ以外の入力を無視する制御

import { Formik, Field, Form } from 'formik';
import { TextField } from '@mui/material';
import { Button } from '@mui/material';
import * as Yup from 'yup';

import React, { useState } from 'react';
// import TextField from '@material-ui/core/TextField';

const MyForm = () => {
  const [value, setValue] = useState('');

  const handleChange = (event) => {
    const newValue = event.target.value;
    if (/^[ヲ-゚]*$/.test(newValue)) {
      setValue(newValue);
    }
  };

  return <TextField value={value} onChange={handleChange} label="半角カナ" />;
};

export default MyForm;

感想

  • 全角から半角に変換する際、1文字1文字マッピングしないといけない部分がとても美しくない

Discussion