はじめに
LaTeXで文章を書いていると、しばしば特殊文字(ラテン文字等)の文字化けが発生します。例えば、コピペしたBibTeXにヨーロッパ圏の著者がいたとか。一番安直な解決方法は特殊文字をLaTeXコマンドに変換することです。そこで、特殊文字をLaTeXコマンドへ変換するWebアプリ(DeepLやShaper風)をReactとMaterial UIで作成してみました。
実装
今回は「新しい React アプリを作る」の「Create React App」を参考にして、シングルページアプリケーションを作成していきます。完成版は以下の通りです。
開発環境
あなたのマシンに Node >= 14.0.0 及び npm >= 5.6 の環境が必要です。
と記載してあったので、nodeとnpmのバージョンを確認しておきます。
$ node -v
v16.8.0
$ npm -v
7.21.0
雛形の作成
プロジェクトを作成します。
npx create-react-app special-character-to-latex-cmd-app
今回はMaterial UIのコンポーネントを使用するため、そのインストールを行います。
cd special-character-to-latex-cmd-app
npm install @mui/material @emotion/react @emotion/styled
続いて、src
下にcomponents
ディレクトリを作成し、その下にApp.js
、Form.js
、LaTeXCmdTable.js
を作成します。(ディレクトリ構造は「Example Projects」の「Calculator」を参考にしています。)
src/
├── components
│ ├── App.js
│ ├── App.test.js
│ ├── Form.css
│ ├── Form.js
│ └── LatexCmdTable.js
├── index.css
├── index.js
├── latex-cmd.json
├── reportWebVitals.js
└── setupTests.js
Form.js
では特殊文字をLaTeXコマンドへ変換するためのテキストフォームを提供するコンポーネントを、LaTeXCmdTable.js
では特殊文字とLaTeXコマンドの対応表を表示するためのコンポーネントを定義しています。App.js
ではForm.js
とLaTeXCmdTable.js
をまとめる親コンポーネントを定義します。
latex-cmd.json
には特殊文字とLaTeXコマンドの対応関係が記述されています。
{
"à": "{\\` a}",
"è": "{\\` e}",
"ì": "{\\` i}",
"ò": "{\\` o}",
"ù": "{\\` u}",
"À": "{\\` A}",
"È": "{\\` E}",
}
続いて、編集が必要な各ファイルについて説明します。
index.js
index.js
はReactアプリを実行する際、一番最初に呼び出されるファイルです。ReactDOM.render
メソッドを用いて、<App>
コンポーネントをindex.html
のid="root"
へ出力しています。
ちなみに、<React.StrictMode>
は子孫要素に対して付加的な検査をしたり、警告をするための機能だそうです。(参考:strict モード)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
App.js
App.js
では、<Form>
と<LatexCmdTable>
の2つのコンポーネントを配置し、その間に<hr>
を用いて線を引きます。
import React from 'react';
import Form from './Form';
import LatexCmdTable from './LatexCmdTable';
function App() {
return (
<div>
<Form />
<hr size="1" wifth="100%" color="gray"></hr>
<LatexCmdTable />
</div>
);
}
export default App;
Form.js
Form.js
では特殊文字をLaTeXコマンドへ変換するためのテキストフォームを作成します。見た目をかっこよくするために、ここではMaterial UIが提供するTextFieldコンポーネントを使用します。
import TextField from '@mui/material/TextField';
<Form>
は関数コンポーネントを用いて定義します。LaTeXコマンドに変換された出力テキスト(outText
)はuseState
フックを用いて関数内にstate変数として宣言します。
function Form() {
const [outText, setOutText] = useState("");
...
}
export default Form;
<TextField>
コンポーネントは入力フィールド用(name="input text"
)と出力フィールド用(name="output text"
)の2つ配置します。入力フィールドで入力値が変化したとき、コールバック関数handleChange
が呼び出されます。
<TextField
name="input field"
onChange={handleChange}
/>
handleChange
では、入力フィールド内の特殊文字をLaTeXコマンドに変換します。コールバック関数内では、更新された入力値はevent.target.value (string)
からアクセスできます。
replaceメソッドを用いてevent.target.value
に含まれる特殊文字をLaTeXコマンドへ変換します。この時マッチした文字をすべて変換したいので、正規表現を用いています。(RegExp
は正規表現オブジェクトです。)
最後に、setOutText
メソッドを用いて、変換後の値をoutText
にセットします。
const handleChange = (event) => {
tmpText = event.target.value;
Object.keys(latexCmdJson).forEach(function (key) {
tmpText = tmpText.replace(RegExp(key, 'g'), latexCmdJson[key]);
});
setOutText(tmpText);
}
outText
の値は、出力フィールド(name="output text"
)の入力要素(value
)にセットされます。また、InputProps
から<input>
の属性を用いて編集不可に設定します。
<TextField
name="output field"
value={outText}
InputProps={{
readOnly: true,
}}
/>
全体のコード
import React, { useState } from 'react';
import TextField from '@mui/material/TextField';
import './Form.css';
import latexCmdJson from '../latex-cmd.json';
function Form() {
const [outText, setOutText] = useState("");
let tmpText = "";
const handleChange = (event) => {
tmpText = event.target.value;
Object.keys(latexCmdJson).forEach(function (key) {
tmpText = tmpText.replace(RegExp(key, 'g'), latexCmdJson[key]);
});
setOutText(tmpText);
}
return (
<div>
<div>
<TextField
multiline
focused
className="textfield-large"
label="LaTeX (including special characters)"
name="input field"
variant="filled"
rows={6}
margin="normal"
onChange={handleChange}/>
</div>
<div>
<TextField
multiline
focused
className="textfield-large"
label="LaTeX (using escaped codes)"
name="output field"
value={outText}
variant="filled"
rows={6}
margin="normal"
InputProps={{
readOnly: true,
}}/>
</div>
</div>
);
}
export default Form;
.textfield-large {
width: 100%;
}
LaTeXCmdTable.js
LaTeXCmdTable.js
では特殊文字とLaTeXコマンドの対応表を表示するためのコンポーネントを定義します。表はMaterial UIの「Basic table」を参考に作成しました。
import React from 'react';
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Paper from '@mui/material/Paper';
import latexCmdJson from '../latex-cmd.json';
function createData(key, value){
return { key, value };
};
let rows = [];
Object.keys(latexCmdJson).forEach(function (key) {
rows.push(createData(key, latexCmdJson[key]));
});
function LatexCmdTable() {
return (
<div>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 400 }} aria-label="simple table"s>
<TableHead>
<TableRow>
<TableCell>Special characters</TableCell>
<TableCell>LaTeX commands</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow key={row.key}>
<TableCell>{row.key}</TableCell>
<TableCell>{row.value}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</div>
);
}
export default LatexCmdTable;
完成品
実行方法
git clone https://github.com/yakiimo121/special-character-to-latex-cmd-app
cd special-character-to-latex-cmd-app
npm install
npm start