WordPressでInDesignの様な文字組−その⑧

前回 簡易的な 役物詰めを紹介しましたが 禁則処理の問題などが残っているので解決していきます

スポンサーリンク

現状の問題点

現状で把握できている問題点は

現状の問題点
  • 連続する句読点のぶら下がり処理
  • 半角スペースによる禁則処理が効かない改行

の二点です 順に見ていきます

連続する句読点のぶら下がり処理

句読点が連続する場合はぶら下がり処理を行わず ただの半角役物として扱います

php 正規表現式

 // 句読点の検索 単数の句読点のみ ぶら下がり 
 '#' . 
	 '([、。, ]{2,})' . 
	 '|' . 
	 '([、。, ])' . 
 '#uis' => function ( $match ) { 
	 if ( $match[1] ) {// 句読点が2文字以上続いている場合
		 return 
			 '<span class = "thx_punc_punc">' . 
				 $match[1] . 
			 '</span>' . 
			 '<span class = "thx_clps_spc"> </span>'; 
	 } else { // 句読点が1文字のみは ぶら下がり
		 return 
			 '<span class = "thx_punc_wrap">' . 
				 '<span class = "thx_punctuation">' . 
					 $match[2] . 
				 '</span>' . 
			 '</span>' . 
			 '<span class = "thx_clps_spc"> </span>'; 
	 } 
 }, 

正規表現の条件式を 2文字以上 1文字のみ とに場合 ばあい けをします

2文字以上 の場合は ただの半角役物として .thx_punc_punc を付与し 可読性を考慮して .thx_clps_spc の半角スペースを追加します

css 追加分

 .thx_punc_punc { 
	 font-feature-settings: "halt"; 
 } 

半角スペースによる禁則処理が効かない改行

半角スペースが存在する限り そこは改行可能になってしまいます

これを回避するには 禁則処理が効かなくなってしまう不要な半角スペースを取り除く必要があります
これは must です

となると 連続する括弧の場合 両端以外の半角スペースを除去する必要があるため 括弧がすべて半角送りになってしまいます 詰まり過ぎて可読性が落ちてしまうのでは?と心配になりますが

全角送りと半角送り
全角送りと半角送り

こうして比べてみると どちらにも良さがあり 甲乙 がた と感じます

そこで どちらが一般的なのか調べてみると とても解り易いページがありました

この文書は w3.org JIS X 4051 日本語組版規則 もと づいて記述しているようで この上ない指標ルールと そうです

こちらの記述によると 連続する同種括弧はベタ組みとなっているので それに なら います

php 正規表現式

 // 括弧の検索
 '#' . 
	 '[ ({[〔「『【〈《]+' . 
 '#uis' => function ( $match ) { 
	 return 
		 '<span class = "thx_clps_spc"> </span>' . 
		 '<span class = "thx_opening_bracket">' . 
			 $match[0] . 
		 '</span>'; 
 }, 
 '#' . 
	 '[)}]〕」』】〉》 ]+' . 
 '#uis' => function ( $match ) { 
	 return 
		 '<span class = "thx_closing_bracket">' . 
			 $match[0] . 
		 '</span>' . 
		 '<span class = "thx_clps_spc"> </span>'; 
 }, 

正規表現の条件式を 1文字以上 に変更し 始め括弧終わり括弧のそれぞれが連続する場合は一つの span でまとめます

また 両端 括弧の外側 には従来通りに .thx_clps_spc の半角スペースを追加します

css 追加分

特になし

更に この文書をよく見てみると 句読点と終わり括弧もベタ組みになっています つまり こんな感じに更に詰めよと

句読点と終わり括弧はベタ組み
句読点と終わり括弧はベタ組み

ふむ となると 句読点と終わり括弧は併せて処理したほうが良さそうですね あらた めます

句読点と終わり括弧の処理

php 正規表現式

 // 句読点と終わり括弧の検索 後端単数の句読点のみ ぶら下がり 
 '#' . 
	 '([、。,.)}]〕」』】〉》 ]{2,})' . 
	 '|' . 
	 '([、。, ])' . 
	 '|' . 
	 '([)}]〕」』】〉》 ])' . 
 '#uis' => function ( $match ) { 
	 // 句読点や終わり括弧が2文字以上続いている場合
	 if ( $match[1] ) { 
		 // 後端の1文字が句読点で 後端の2文字が同一でなければ ぶら下がり処理
		 if ( 
			 ( 
				 '  ' === mb_substr( $match[1], -1 ) 
				 || 
				 '  ' === mb_substr( $match[1], -1 ) 
				 || 
				 '  ' === mb_substr( $match[1], -1 ) 
				 || 
				 '  ' === mb_substr( $match[1], -1 ) 
			 ) 
			 && 
			 ( mb_substr( $match[1], -1, 1 ) !== mb_substr( $match[1], -2, 1 ) ) 
		 ) { 
			 return 
				 '<span class = "thx_closing_mark">' . 
					 mb_substr( $match[1], 0, -1 ) . 
				 '</span>' . 
				 '<span class = "thx_punc_wrap">' . 
					 '<span class = "thx_punctuation">' . 
						 mb_substr( $match[1], -1 ) . 
					 '</span>' . 
				 '</span>' . 
				 '<span class = "thx_clps_spc"> </span>'; 
		 } else { // ぶら下がり不要
			 return 
				 '<span class = "thx_closing_mark">' . 
					 $match[1] . 
				 '</span>' . 
				 '<span class = "thx_clps_spc"> </span>'; 
		 } 
	 } elseif ( $match[2] ) { // 句読点が1文字のみは ぶら下がり
		 return 
			 '<span class = "thx_punc_wrap">' . 
				 '<span class = "thx_punctuation">' . 
					 $match[2] . 
				 '</span>' . 
			 '</span>' . 
			 '<span class = "thx_clps_spc"> </span>'; 
	 } else { // ぶら下がり不要
		 return 
		 '<span class = "thx_closing_mark">' . 
			 $match[3] . 
		 '</span>' . 
		 '<span class = "thx_clps_spc"> </span>'; 
	 } 
 }, 
 '#' . 
	 '([、。,.)}]〕」』】〉》 ]{2,})' . 
	 '|' . 
	 '([、。, ])' . 
	 '|' . 
	 '([)}]〕」』】〉》 ])' . 
 '#uis' 

正規表現の条件式を

  • 句読点か終わり括弧が2文字以上
  • 句読点が1文字のみ
  • 終わり括弧が1文字のみ

とに場合分けをします

句読点か終わり括弧が2文字以上
 if ( 
	 ( 
		 '  ' === mb_substr( $match[1], -1 ) 
		 || 
		 '  ' === mb_substr( $match[1], -1 ) 
		 || 
		 '  ' === mb_substr( $match[1], -1 ) 
		 || 
		 '  ' === mb_substr( $match[1], -1 ) 
	 ) 
	 && 
	 ( mb_substr( $match[1], -1, 1 ) !== mb_substr( $match[1], -2, 1 ) ) 
 )  

句読点か終わり括弧が2文字以上 の場合 ぶら下がり処理が必要な可能性があるので 判別を行います

判別の基準は

  • 後端の1文字が句読点で終わっている

  • 後端の2文字が同一ではない

とします

 { 
	 return 
		 '<span class = "thx_closing_mark">' . 
			 mb_substr( $match[1], 0, -1 ) . 
		 '</span>' . 
		 '<span class = "thx_punc_wrap">' . 
			 '<span class = "thx_punctuation">' . 
				 mb_substr( $match[1], -1 ) . 
			 '</span>' . 
		 '</span>' . 
		 '<span class = "thx_clps_spc"> </span>'; 
 } 

上記の判別基準に合致した場合 まずは後端の1文字を除いた部分に thx_closing_mark を付与し 半角送りとします

続いて 後端の1文字にぶら下がり処理を行います

css
 /*  括弧など  */ 
 .thx_closing_mark { 
	 font-feature-settings: "halt"; 
 } 
 else { // ぶら下がり不要
	 return 
		 '<span class = "thx_closing_mark">' . 
			 $match[1] . 
		 '</span>' . 
		 '<span class = "thx_clps_spc"> </span>'; 
 } 

合致しない場合はぶら下がり処理の必要がないので 検出された 句読点か終わり括弧が2文字以上 全体に thx_closing_mark を付与して半角送りとし thx_clps_spc の半角スペースを追加します

句読点が1文字のみ
 elseif ( $match[2] ) { // 句読点が1文字のみは ぶら下がり
	 return 
		 '<span class = "thx_punc_wrap">' . 
			 '<span class = "thx_punctuation">' . 
				 $match[2] . 
			 '</span>' . 
		 '</span>' . 
		 '<span class = "thx_clps_spc"> </span>'; 
 } 

句読点が1文字のみ が検出された場合は 従来通りにぶら下がり処理を行います

終わり括弧が1文字のみ
 else { // ぶら下がり不要
	 return 
	 '<span class = "thx_closing_mark">' . 
		 $match[3] . 
	 '</span>' . 
	 '<span class = "thx_clps_spc"> </span>'; 
 } 

終わり括弧が1文字のみ が検出された場合は 半角送りを行うクラスとして thx_closing_mark を付与し thx_clps_spc の半角スペースを追加します

始め括弧
 // 始め括弧の検索
 '#' . 
	 '[ ({[〔「『【〈《]+' . 
 '#uis' => function ( $match ) { 
	 return 
		 '<span class = "thx_clps_spc"> </span>' . 
		 '<span class = "thx_opening_mark">' . 
			 $match[0] . 
		 '</span>'; 
 }, 

特に変更はありませんが 終わり括弧類のクラス名を thx_closing_mark と変更したので こちらも併せて thx_opening_mark と変更します

css
 /*  括弧など  */ 
 .thx_opening_mark, 
 .thx_closing_mark { 
	 font-feature-settings: "halt"; 
 } 

その他の調整

その他にも細々 こまごま とした調整を ほどこ していますので ざっと概略のみ紹介しておきます

ゼロ幅スペース

例えば 。」 ではなく と詰めずに表記したいケースもあるかもしれません それを実現するためにゼロ幅スペースを り入れました 詰めずに表記したい箇所に &#x200b; とゼロ幅スペースを挿入する事により 。” 」” が連続しなくなるため thx_clps_spc が挿入されます

しかし ゼロ幅とは言えスペースに変わりはないので 改行可能位置となる事に注意が必要です しくは その性質を利用し 改行しても良い箇所に えて挿入しておくのもアリかもしれません

相殺スペースに隣接する和欧間スペース

相殺スペースは二分幅の半角スペース 和欧間スペースは四分幅の半角スペースと どちらも実態は半角スペースなので単一化されるのですが 二分幅なのか四分幅なのか表示結果が曖昧 あいまい になるので 隣接する際は和欧間スペースを除去します

括弧内に隣接する和欧間スペース

和欧間スペースも実態は半角スペースなので改行可能位置です つまり 括弧の禁則処理が効かなくなるケースがありますので 括弧内に隣接する和欧間スペースを除去します

文字種の追加

w3 の文書に 2.1.1  日本語組版に使用する文字なる項目がありましたので 役物の文字種を追加します

<code> 内では詰めを解除

全角役物が半角幅で表示されてしまい 誤認識の恐れがあるのでこれを解除します

ソースコード

check
  • カスタマイズは自己責任でお願いします。
  • wp-cocoon.comサイトのサポート対象外となります。

php

 // 簡易的な日本語組版
 function thx_typesetting( $the_content ) { 
	 //html をテキストとタグに分解
	 $pairing = html_split_text_tag( $the_content ); 

	 // ペアリングを span しながら結合
	 $the_content = ''; 
	 foreach ( $pairing as $value ) { 
		 $str = trim( $value[0] ); 
		 $tag = $value[1]; 

		 if ( 
			 ( '</style>' === $tag ) 
			 || 
			 ( '</rt>' === $tag ) 
			 || 
			 ( '</li>' === $tag ) 
		 ) { 
			 $the_content .= $str; 
		 } else { 
			 $the_content 
			 .= preg_replace_callback_array( 
				 [ 
					 // 欧文の検索 ゼロスペースを含む場合は2文字以上 
					 '#' . 
						 '[ !-;=-~\p{Ll}\x{200b}]{2,}' . 
						 '|' . 
						 '[ !-;=-~\p{Ll}]+' . 
					 '#uis' => function ( $match ) { 
						 return 
							 '<span class = "thx_wao_spc"> </span>' . 
							 '<span class = "thx_pwid">' . 
								 $match[0] . 
							 '</span>' . 
							 '<span class = "thx_wao_spc"> </span>'; 
					 }, 
					 // 句読点と終わり括弧の検索 後端単数の句読点のみ ぶら下がり 
					 '#' . 
						 '([、。,.’”)〕]}〉》」』】 ]{2,})' . 
						 '|' . 
						 '([、。, ])' . 
						 '|' . 
						 '([’”)〕]}〉》」』】 ])' . 
					 '#uis' => function ( $match ) { 
						 // 句読点や終わり括弧が2文字以上続いている場合
						 if ( $match[1] ) { 
							 // 後端の1文字が句読点で 後端の2文字が同一でなければ ぶら下がり処理
							 if ( 
								 ( 
									 '  ' === mb_substr( $match[1], -1 ) 
									 || 
									 '  ' === mb_substr( $match[1], -1 ) 
									 || 
									 '  ' === mb_substr( $match[1], -1 ) 
									 || 
									 '  ' === mb_substr( $match[1], -1 ) 
								 ) 
								 && 
								 ( mb_substr( $match[1], -1, 1 ) !== mb_substr( $match[1], -2, 1 ) ) 
							 ) { 
								 return 
									 '<span class = "thx_closing_mark">' . 
										 mb_substr( $match[1], 0, -1 ) . 
									 '</span>' . 
									 '<span class = "thx_punc_wrap">' . 
										 '<span class = "thx_punctuation">' . 
											 mb_substr( $match[1], -1 ) . 
										 '</span>' . 
									 '</span>' . 
									 '<span class = "thx_clps_spc"> </span>'; 
							 } else { // ぶら下がり不要
								 return 
									 '<span class = "thx_closing_mark">' . 
										 $match[1] . 
									 '</span>' . 
									 '<span class = "thx_clps_spc"> </span>'; 
							 } 
						 } elseif ( $match[2] ) { // 句読点が1文字のみは ぶら下がり
							 return 
								 '<span class = "thx_punc_wrap">' . 
									 '<span class = "thx_punctuation">' . 
										 $match[2] . 
									 '</span>' . 
								 '</span>' . 
								 '<span class = "thx_clps_spc"> </span>'; 
						 } else { // ぶら下がり不要
							 return 
							 '<span class = "thx_closing_mark">' . 
								 $match[3] . 
							 '</span>' . 
							 '<span class = "thx_clps_spc"> </span>'; 
						 } 
					 }, 
					 // 中点の検索
					 '#' . 
						 '[ ・:; ]+' . 
					 '#uis' => function ( $match ) { 
						 return 
							 '<span class = "thx_clps_spc"> </span>' . 
							 '<span class = "thx_mid_dot">' . 
								 $match[0] . 
							 '</span>' . 
							 '<span class = "thx_clps_spc"> </span>'; 
					 }, 
					 // 始め括弧の検索
					 '#' . 
						 '[ ‘“(〔[{〈《「『【]+' . 
					 '#uis' => function ( $match ) { 
						 return 
							 '<span class = "thx_clps_spc"> </span>' . 
							 '<span class = "thx_opening_mark">' . 
								 $match[0] . 
							 '</span>'; 
					 }, 
					 // 括弧内の和欧間スペースを除去 禁則対策 
					 '#' . 
						 '(<span class = "thx_opening_mark">[ ‘“(〔[{〈《「『【]+</span>)' . 
						 '(<span class = "thx_wao_spc"> </span>)' . 
					 '#uis' => function ( $match ) { 
						 return $match[1]; 
					 }, 
					 '#' . 
						 '(<span class = "thx_wao_spc"> </span>)' . 
						 '(<span class = "thx_closing_mark">[、。,.’”)〕]}〉》」』】 ]+</span>)' . 
					 '#uis' => function ( $match ) { 
						 return $match[2]; 
					 }, 
					 // 欧文と役物以外を全角処理に
					 '#' . 
						 '[^ !-~\p{Ll}、。, ・:; ‘“(〔[{〈《「『【’”)〕]}〉》」』】 ]{2,}' . 
						 '|' . 
						 '[^ !-~\p{Ll}\x{200b}、。, ・:; ‘“(〔[{〈《「『【’”)〕]}〉》」』】 ]+' . 
					 '#uis' => function ( $match ) { 
						 return '<span class = "thx_fwid">' . $match[0] . '</span>'; 
					 }, 
					 // ゼロスペース処理
					 '#' . 
						 '[\x{200b}]+' . 
					 '#uis' => function ( $match ) { 
						 return '<span class = "thx_zero_spc">' . $match[0] . '</span>'; 
					 }, 
				 ], 
				 $str 
			 );//$the_content .= preg_replace_callback_array() 
		 }//else ( '</style>' === $tag ) 
		 $the_content .= $tag; 
	 }//foreach ( $pairing as $value ) 

	 // 重複する thx_clps_spc を削除
	 $the_content 
		 = str_replace( 
			 '<span class = "thx_clps_spc"> </span><span class = "thx_clps_spc"> </span>', 
			 '<span class = "thx_clps_spc"> </span>', 
			 $the_content 
		 ); 

	 // 相殺スペースは和欧間スペースを吸収
	 $the_content 
		 = str_replace( 
			 array( 
				 '<span class = "thx_clps_spc"> </span><span class = "thx_wao_spc"> </span>', 
				 '<span class = "thx_wao_spc"> </span><span class = "thx_clps_spc"> </span>', 
			 ), 
			 '<span class = "thx_clps_spc"> </span>', 
			 $the_content 
		 ); 

	 // 括弧内の <a> などを禁則対策
	 $the_content 
		 = preg_replace_callback_array( 
			 [ 
				 '#' . 
					 '(<span class = "thx_opening_mark">[ ‘“(〔[{〈《「『【]+</span>)' . 
					 '(<[^>]*>)' . 
					 '(<span class = "thx_wao_spc"> </span>)' . 
				 '#uis' => function ( $match ) { 
					 return $match[1] . $match[2]; 
				 }, 
				 '#' . 
					 '(<span class = "thx_wao_spc"> </span>)' . 
					 '(<[^>]*>)' . 
					 '(<span class = "thx_closing_mark">[、。,.’”)〕]}〉》」』】 ]+</span>)' . 
				 '#uis' => function ( $match ) { 
					 return $match[2] . $match[3]; 
				 }, 
			 ], 
			 $the_content 
		 ); 

	 return $the_content; 
 }//thx_typesetting( $the_content ) 

css

 /*  禁則処理と両端揃え */ 
 body { 
	 line-break: strict; 
	 text-align: justify; 
 } 

 /*  全角化  */ 
 .thx_fwid { 
	 font-feature-settings: "fwid"; 
 } 

 /*  プロポーショナル化  */ 
 .thx_pwid { 
	 font-feature-settings: "pwid"; 
 } 

 /*  ゼロ幅スペース &#x200b;  \x{200b}  */ 
 .thx_zero_spc { 
	 -webkit-user-select: none; 
	 user-select: none; 
 } 

 /*  和欧間スペース  */ 
 .thx_wao_spc { 
	 font-family: Kosugi; 
	 font-size: 0.5em; 
	 line-height: 0; 
	 -webkit-user-select: none; 
	 user-select: none; 
 } 

 code .thx_wao_spc { 
	 display: none; 
 } 

 /*  相殺スペース  */ 
 .thx_clps_spc { 
	 -webkit-user-select: none; 
	 user-select: none; 
 } 

 .chrome .thx_clps_spc { 
	 font-family: sans-serif; 
	 font-feature-settings: "hwid"; 
 } 

 .gecko .thx_clps_spc { 
	 font-family: Kosugi; 
	 line-height: 0; 
 } 

 .safari .thx_clps_spc { 
	 font-family: Kosugi; 
	 line-height: 0; 
 } 

 body.amp .thx_clps_spc { 
	 font-family: initial; 
 } 

 code .thx_clps_spc { 
	 display: none; 
 } 

 /*  句読点  */ 
 .thx_punc_wrap { 
	 position: relative; 
	 display: inline-block; 
 } 

 .thx_punc_punc { 
	 font-feature-settings: "halt"; 
 } 

 .thx_punc_clbr { 
	 font-feature-settings: "halt"; 
 } 

 .chrome .thx_punc_wrap + .thx_clps_spc { 
	 font-feature-settings: "fwid"; 
 } 

 .gecko .thx_punc_wrap + .thx_clps_spc { 
	 font-size: 2em; 
 } 

 .safari .thx_punc_wrap + .thx_clps_spc { 
	 font-size: 2em; 
 } 

 .thx_punctuation { 
	 position: absolute; 
	 font-feature-settings: "halt"; 
	 line-height: 1em; 
 } 

 code .thx_punc_wrap .thx_punctuation { 
	 position: relative; 
	 font-feature-settings: "fwid"; 
	 bottom: initial; 
 } 

 .chrome .thx_punctuation { 
	 bottom: -0.1em; 
 } 

 .gecko .thx_punctuation { 
	 bottom: -0.15em; 
 } 

 .safari .thx_punctuation { 
	 bottom: -0.15em; 
 } 

 /*  中黒  */ 
 :not(code)>.thx_mid_dot { 
	 font-feature-settings: "halt"; 
 } 

 :not(code)>.thx_clps_spc + .thx_mid_dot { 
	 margin-left: -0.25em; 
 } 

 :not(code)>.thx_mid_dot + .thx_clps_spc { 
	 margin-left: -0.25em; 
 } 

 /*  括弧など  */ 
 :not(code)>.thx_opening_mark, 
 :not(code)>.thx_closing_mark { 
	 font-feature-settings: "halt"; 
 } 

まとめ

うん 簡易的とは言え やりたかった事の ほとん どが実装できました

また w3.org の文書を知り得た事が大きいです いや 本来ならね こーゆーのは最初に調べておく事なんでしょうけど るとは思わなかったので調べようともせず 経験とカンと好みのみで進めてきました

この文書のルールに近づけていけば いつの日か 簡易的な かんむり を外す事も出来そうですね おそらくしませんが、、、 まぁ クリティカルな問題があったり カンタンに実装できそうな項目があれば参照していきたいと思います

続いては このシリーズ WordPress InDesign の様な文字組 を汎用プラグインとしてまとめ Cocoon 用のプラグインとしてまとめる予定です

コメント