【ワレコJavaScript】正規表現で文字列置換・部分文字列カウント・部分文字列Index

この記事は約18分で読めます。
スポンサーリンク

ワテの場合、WEBプログラミングの文法が中々覚えられない。

例えば

<div id="divID">・・・</div>

この中に何らかの文字列を書き込みたい場合に、

$('#divID').html('文字列');				// jQuery
document.getElementById('divID').innerHTML = '文字列'	// JavaScript

とやれば良い。

 

では複数行を書き込みたい場合には?

$('#divID').html('文字列1\r\n文字列2\r\n文字列3');   // ×

$('#divID').html('文字列1<br/>文字列2<br/>文字列3'); // 〇

のどっち?

 

では

<p>・・・</p>

<textarea>・・・</textarea>

の場合は?

 

まとめると以下の通り。

$('#divID').html('文字列1<br/>文字列2<br/>文字列3');	//〇 これで三行に改行出来る

$('#pID').html('文字列1<br/>文字列2<br/>文字列3');	//〇 これで三行に改行出来る

$('#textareaID').html('文字列1\r\n文字列2\r\n文字列3');	//〇 これで三行に改行出来る

 

この記事は、改行コード(\r\n)や<br/>の扱いに関するワテの備忘録。

スポンサーリンク
ワテ推薦のプログラミングスクールで学ぶ
スポンサーリンク
スポンサーリンク

改行コード(\r\n, \r, \n)を <br/> に置換する

例えばtextareaに入力されている文字列を読み取ってdivに表示したい場合には改行コードを置き換える必要がある。

textareaの改行コードは \r\n, \r, \n などだ。

 OS  改行文字  記号  説明(引用元 改行コードのWikipedia)
Windows \r\n  

CR(復帰、0x0D)

+

LF(改行、0x0A)

CP/M、MP/M、MS-DOS、OS/2、Microsoft Windows。
Unix \n LF(改行、0x0A) UNIXやUnix系のシステム。Linux、AIX、Xenix、macOS、BeOS、Amiga、RISC OSなど。 
Mac \r  CR(復帰、0x0D)  コモドールによるシステム、Apple IIファミリ、Mac OS(バージョン9まで)、OS-9。 

一方、

div, pの改行コードは <br/> だ。

以下のJavaScriptを実行すると、textareaに入力されている文字列を読み取って、別のdivに表示出来る。

var textareaHtml = $('#textareaID').html();

var divHtml = textareaHtml.replace(/(?:\r\n|\r|\n)/g, '<br />');

var divHtml2 = textareaHtml.replace(new RegExp('\r\n|\r|\n', 'g'),'<br />'); //こう言う書き方もある。

$('#divID').html(divHtml);

このプログラムでは、改行文字を置換してdivで正しく表示出来るようにしている。

正規表現の説明

/(?:\r\n|\r|\n)/g

の部分は、

/\r\n|\r|\n/g

でも良い。

その意味は、

\r\n

\r

\n

のどれかの文字列が有れば( | 記号はOR条件)それを文字列 ‘<br />’ に置換する。

g

gオプションは、文字列の中に条件にマッチする文字列が複数有っても、それら全部を置換対象とする。

もしgを付けないと、最初に出現する改行コードのみ ‘<br />’ に置換される。

gはグローバル(Global)のgだ。

他に良く使うオプションとしては i がある。ignore case(大文字・小文字を区別しない)だ。今の例では使わない。

パターンを丸カッコで囲うとキャプチャできる

正規表現パターンを丸カッコで囲う事が出来る。

(パターン)

そうすると、このパターンにマッチした部分を $1 , $2 , $3, …のように参照出来る。

var divHtml = textareaHtml.replace(/(\r\n|\r|\n)/g, '[改行コード発見]$1'); 

 

キャプチャしたくない場合には、?: を付ける

(?:パターン)

とすればこのパターンにマッチしてもキャプチャされない。

 

ここで疑問を持つ人も居るだろう。

キャプチャしたくないんなら、最初から丸カッコで囲わなければいいんじゃないの?

確かにそうなのだが、複雑な正規表現パターンを記述している場合には部分的なパターンを丸カッコで囲ってやるほうが分かり易く記述出来る。

でもキャプチャはしたくない。

そんな時に ?: を付けると良い(ワテの場合)。

文字列中にある部分文字列の数を数える

プログラミングをしていると、文字列中に特定の部分文字列が何回出現するのか知りたい場合が時々ある。

JavaScriptの場合は以下のようにすれば部分文字列の出現回数を数える事が出来る。

var count = (textareaHtml.match(/\r\n|\r|\n/g) || []).length;

この例では、テキストエリアに入力されている文字列の中に、改行が何個出現するのかを数えている。

|| []

の意味は、もし部分文字列が一つも見付からずにmatch()結果がnullの場合には、null.length を求めると例外が発生する。

それを回避する小細工だ。

match()の結果と空の配列との論理ORを計算する事で、もしmatch()の結果がnullなら空配列のlengthを計算するのでそれは0になる。

ちなみに、JavaScriptで使える論理演算子 論理AND(&&)論理OR(||)論理NOT(!)の使い方は以下の通り。

演算子 使用法 説明
論理 AND(&&) expr1&&expr2 expr1 を false と見ることができる場合は、expr1 を返します。そうでない場合は、expr2 を返します。したがって、真偽値と共に使われた場合、 演算対象の両方が true ならば、&& は、true を返し、そうでなければ、false を返します。
論理 OR (||) expr1||expr2 expr1 を true と見ることができる場合は、expr1 を返します。そうでない場合は、expr2 を返します。したがって、真偽値と共に使われた場合、 演算対象のどちらかが true ならば、|| は、true を返し、両方とも false の場合は、false を返します。
論理 NOT (!) !expr 単一の演算対象が true と見ることができる場合は、false を返します。そうでない場合は、true を返します。

引用元 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_Operators

 

文字列中にある部分文字列の開始位置を全部取得する

文字列の中にある部分文字列の開始位置(0から数えるインデックス)を全部取得してみよう。

即席で関数を作ってみた。

function GetSubstrStartPosAll(str, substr) {

	var re = new RegExp(substr, 'gi');
	var results = new Array(); // 結果を入れる
	var arr = re.exec(str);
	while (arr) {
		results.push(arr.index);
		arr = re.exec(str);
	}
	return results;
};
 
var arr1 = GetSubstrStartPosAll(textareaHtml, '文字列'); // [0,5,10]
var arr2 = GetSubstrStartPosAll('文字列1\r\n文字列2\r\n文字列3', '文字列'); // [0,6,12]

実行結果は、整数値を保持する配列になる。

結果を入れる配列は new Array() で作成しているので見付からない場合もnullではなく[]、つまり空の配列がリターンされる。

 

さてこの関数を実行してみたところ、textareaの改行コードに関して一つ気づいた事がある。

それは、以下のように三行の文字列をtextareaに記入する。

$('#textareaID').html('文字列1\r\n文字列2\r\n文字列3');
var textareaHtml = $('#textareaID').html();

その文字列を textareaHtml に読み取る。

この文字列に対して上で作成したGetSubstrStartPosAll()関数を実行すると

var arr1 = GetSubstrStartPosAll(textareaHtml , '文字列');
// arr1 = [0,5,10] だった。

が得られた。

一方、以下の文字列に対して同じくGetSubstrStartPosAll()を実行すると、

var str = '文字列1\r\n文字列2\r\n文字列3';
var arr2= GetSubstrStartPosAll(str, '文字列')
// arr = [0,6,12] だった。

となった。

要するに <textarea>・・・</textarea> 内のhtmlでは、改行は2文字の \r\n ではなくて1文字のようだ。

調べたら \n (LF、改行、0x0A)だった(Windows10上のChrome, IE, FFで)。

textareaの改行コードはHTMLの仕様で \n の1文字に決まっているのかどうかは未確認だ。

関連しそうなW3.orgのサイトを見付けたが英語なので良く分からん。日本語でも分からんかも。

https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4

 

と言う事で、プログラムにおいて改行を扱う場合には、

  • CR+LF(\r\n=0x0D,0x0A=復帰,改行)
  • CR(\r=0x0D=復帰)
  • LF(\n=0x0A=改行)

のどれが来るか分からないので、どれが来ても対処できるプログラムを書いておくと良いだろう。

文字列の前後の半角空白、全角空白、タブ、改行、復帰などを除去する

文字列の前後の空白文字を除去したい場合には、.trim() メソッドを使えば良い。

でも、ここでは同じ処理を正規表現でやってみた。

var trim_result1 = '  \r\n    \t\t\あああ  \r\n  \t\t'.replace(/^\s+|\s+$/g, '');
var trim_result2 = '  \r\n    \t\t\あああ  \r\n  \t\t'.trim();

どちらの場合も

'あああ'

が得られる。

なお、空白文字とは単なる半角スペースだけでなく、正規表現で言うと \s に相当する文字だ。

具体的には \s は [ \f\n\r\t\v] と同じ意味になる。

メタキャラクタの全リストと正規表現でのメタキャラクタの動作

参考までに、\sだけでなくメタキャラクタの全リストと、正規表現でのメタキャラクタの動作をマイクロソフト社のサイトから引用させてもらう。

文字 説明
\ 次に続く文字が特殊文字、リテラル、後方参照、または 8 進エスケープであることを示します。たとえば、”n” は文字 “n” と一致します。’\n’ は改行文字と一致します。”\\” は “\” と、”\(” は “(” と一致します。
^ 入力文字列の先頭と一致します。RegExp オブジェクトの Multiline プロパティが設定されている場合、^ は ‘\n’ または ‘\r’ の直後にも一致します。
$ 入力文字列の末尾と一致します。RegExp オブジェクトの Multiline プロパティが設定されている場合、$ は ‘\n’ または ‘\r’ の直前にも一致します。
* 直前のサブ式と 0 回以上一致します。たとえば、”zo*” は “z” とも “zoo” とも一致します。* は {0,} と同じ意味になります。
+ 直前のサブ式と 1 回以上一致します。たとえば、”zo+” は “zo” や “zoo” とは一致しますが、”z” とは一致しません。+ は {1,} と同じ意味になります。
? 直前のサブ式と 0 回または 1 回一致します。たとえば、”do(es)?” は “do” または “does” の”do” と一致します。? は {0,1} と同じ意味になります。
{n} n には 0 以上の整数を指定します。正確に n 回一致します。たとえば、’o{2}’ は “Bob” の ‘o’ とは一致しませんが、”food” の 2 つの o とは一致します。
{n,} n には 0 以上の整数を指定します。少なくとも n 回一致します。たとえば、’o{2}’ は “Bob” の “o” とは一致しませんが、”foooood” のすべての o とは一致します。’o{1,}’ は ‘o+’ と同じ意味になります。’o{0,}’ は ‘o*’ と同じ意味になります。
{n,m} m および n には 0 以上の整数を指定します。n は 以下です。n ~ m 回一致します。たとえば、”o{1,3}” は “fooooood” の最初の 3 つの o と一致します。’o{0,1}’ は ‘o?’ と同じ意味になります。カンマと数の間には、スペースを入れないでください。
? ほかの修飾子 (*, +, ?, {n}, {n,}, {n,m}) の直後に指定すると、一致パターンを制限することができます。既定のパターンでは、できるだけ多数の文字列と一致するのに比べて、制限されたパターンでは、できるだけ少ない文字列と一致します。たとえば、文字列 “oooo” に対して、’o+?’ を指定すると 1 つの “o” と一致し、’o+’ を指定するとすべての ‘o’ と一致します。
. “\n” を除く任意の 1 文字に一致します。’\n’ など、任意の文字と一致するには、'[.\n]’ などのパターンを指定します。
(pattern) pattern と一致した文字列を記憶します。記憶した一致文字列は、VBScript の SubMatches コレクションまたは JScript の $0…$9 プロパティを使用して Matches コレクションから取得できます。かっこ ( ) と一致するには、’\(‘ または ‘\)’ を指定します。
(?:pattern) pattern と一致しても、その文字列は記憶されず、後で使用することはできません。”or” を意味する (|) を使用してパターンの一部を結合するときに便利です。たとえば、’industry|industries’ と指定する代わりに、’industr(?:y|ies)’ と指定する方が簡単です。
(?=pattern) pattern で指定した文字列が続く場合に一致と見なされます (肯定先読み)。一致した文字列は記憶されず、後で使用することはできません。たとえば、”Windows(?=95|98|NT|2000)” は “Windows 2000 ” の “Windows” には一致しますが、”Windows 3.1″ の “Windows ” には一致しません。先読み処理では、読み進まれた文字は処理済みとは見なされません。一致の検出後、次の検索処理は先読みされた文字列の後からではなく、一致文字列のすぐ後から開始されます。
(?!pattern) pattern で指定しない文字列が続く場合に一致と見なされます (否定先読み)。一致した文字列は記憶されず、後で使用することはできません。たとえば、”Windows(?=95|98|NT|2000)” は “Windows 3.1” の “Windows” には一致しますが、”Windows 2000″ の “Windows ” には一致しません。先読み処理では、読み進まれた文字は処理済みとは見なされません。一致の検出後、次の検索処理は先読みされた文字列の後からではなく、一致文字列のすぐ後から開始されます。
x|y x または y と一致します。たとえば、’z|food’ は “z” または “food” と一致します。”(z|f)ood” は “zoo” または “food” に一致します。
[xyz] 文字セットを指定します。角かっこで囲まれた文字の中のいずれかに一致します。たとえば、'[abc]’ は “plain” の ‘a’ と一致します。
[^xyz] 除外する文字セットを指定します。角かっこで囲まれた文字以外の文字に一致します。たとえば、'[^abc]’ は “plain” の ‘p’ と一致します。
[a-z] 除外する文字の範囲を指定します。指定された範囲にある文字と一致します。たとえば、”[a-z]” は小文字の英字 “a” から “z” の範囲にある任意の文字と一致します。
[^a-z] 否定の文字の範囲。指定範囲以外の文字と一致します。たとえば、”[^a-z]” は小文字の英字 “a” から “z” の範囲外にある任意の文字と一致します。
\b 単語の境界と一致します。単語の境界とは、単語とスペースとの間の位置のことです。たとえば、’er\b’ は “never” の ‘er’ と一致しますが、”verb” の ‘er’ とは一致しません。
\B 単語境界以外と一致します。たとえば、’er\B’ は “verb” の ‘er’ と一致しますが、”never” の ‘er’ とは一致しません。
\cx x で指定した制御文字と一致します。たとえば、\cM は Control-M またはキャリッジ リターン文字と一致します。の値は、A-Z または a-z の範囲内で指定します。それ以外を指定すると、リテラル文字 “c” と認識されます。
\d 任意の 10 進文字と一致します。[0-9] と同じ意味になります。
\D 10 進数字以外の任意の 1 文字と一致します。[^0-9] と同じ意味になります。
\f フォームフィード文字と一致します。\x0c および \cL と同じ意味になります。
\n 改行文字と一致します。\x0a および \cJ と同じ意味になります。
\r キャリッジ リターン文字と一致します。\x0d および \cM と同じ意味になります。
\s スペース、タブ、フォームフィードなどの任意の空白文字と一致します。[ \f\n\r\t\v] と同じ意味になります。
\S 空白文字以外の任意の文字と一致します。[^ \f\n\r\t\v] と同じ意味になります。
\t タブ文字と一致します。\x09 および \cI と同じ意味になります。
\v 垂直タブ文字と一致します。\x0b および \cK と同じ意味になります。
\w 単語に使用される任意の文字と一致します。アンダースコアも含まれます。'[A-Za-z0-9_]’ と同じ意味になります。
\W 単語に使用される文字以外の任意の文字と一致します。'[^A-Za-z0-9_]’ と同じ意味になります。
\xn に指定した 16 進数のエスケープ値と一致します。16 進数のエスケープ値は 2 桁である必要があります。たとえば、’\x41′ は “A” と一致します。’\x041′ は ‘\x04’ および “1” と同じ意味になります。この表記により、正規表現で ASCII コードを使用できるようになります。
\num num と一致します。num には正の整数を指定します。既に見つかって記憶されている部分と一致します。たとえば、'(.)\1′ は、連続する 2 つの同じ文字と一致します。
\n 8 進エスケープ値または後方参照を指定します。\n の前に少なくとも n 個の記憶されたサブ式がある場合は、n は後方参照になります。それ以外の場合で n が 8 進数値 (0-7) である場合は、n は 8 進エスケープです。
\nm 8 進数のエスケープ値または後方参照を指定します。\nm の前に少なくとも nm 個の記憶されたサブ式がある場合は、nm は後方参照になります。\nm の前に少なくとも n 個の記憶されたサブ式がある場合は、n が後方参照になります。どちらの条件にも当てはまらない場合で および m が 8 進数 (0-7) である場合は、\nm は 8 進数のエスケープ値 nm と一致します。
\nml n が 8 進数値 (0-3) で、m と l が 8 進数値 (0-7) の場合、8 進エスケープ値 nml と一致します。
\un n と一致します。n には Unicode 文字で表した 4 桁の 16 進数を指定します。たとえば、\u00A9 は著作権の記号 (©)と一致します。

引用元 https://msdn.microsoft.com/ja-jp/library/cc392020.aspx?f=255&MSPPError=-2147217396

ワテの場合、この表の半分くらいは理解出来ているつもりだ。あくまで自己申告だ。

まとめ

当記事では、JavaScriptやTypeScriptの正規表現の基本的な使い方を備忘録としてまとめた。

当記事で紹介した内容は、

  • 正規表現を使った文字列置換、
  • 部分文字列の出現回数のカウント、
  • 部分文字列の出現位置Indexの全取得

などである。

また、HTMLの要素のうち、div, p, textareaに複数行を入力する場合の改行文字について調査した。

div, p などは<br/>で改行する。

textareaは \n で改行する事が判明した。

正規表現の本を読む

正規表現と言えばこの本が有名だ。

大型本で 528ページもある。一体全体どうやったら500ページ超えの本を書けるのだろうか。

出版社はもちろんオライリージャパン。

新進気鋭で前途有望な人はこんな本で勉強するのが良いだろう。

前途多難な人には何かお勧めなのかな。

探してみた。

こう言うのはどうだろうか。運が開けるかも知れない。

何事もやる気が肝心だ。

スポンサーリンク
ワテ推薦のプログラミングスクールで学ぶ
コメント募集

この記事に関して何か質問とか補足など有りましたら、このページ下部にあるコメント欄からお知らせ下さい。

HTMLJavaScriptjQuery
スポンサーリンク
warekoをフォローする
スポンサーリンク
われこ われこ

コメント