HTMLの形をしたテキスト(すべて文字列なのでDOMやNodeなどは存在しない)にあるnbspをカウントしてp要素に該当する文字列にクラスとして追加したいのですが、この様に文字列の部分的な処理を連続して行うにはどうしたら良いでしょうか?
ちなみに、この処理はMeryというテキストエディタのマクロとして利用するつもりなのですが、マクロ機能でJavaScriptがそのまま使える様なので、テキストエディタの事は特に考慮せず、普通のJavaScriptの質問として見て頂いて構いません。
<!-- HTMLの形をしていますが実際にはテキスト(文字列)です -->
<!-- beforeはdiv直下のみで後は全てafter -->
<div>
<p>段落</p>
<p>段落</p>
</div>
<div>
<p>段落</p>
<p>段落</p>
</div>
<div>
<p>段落</p>
<p>段落</p>
</div>
↑を↓にしたい。
<!-- HTMLの形をしていますが実際にはテキスト(文字列)です -->
<!-- beforeはdiv直下のみで後は全てafter -->
<div>
<p class="before-1 after-6">段落</p>
<p class="after-2">段落</p>
</div>
<div>
<p class="before-2 after-4">段落</p>
<p class="after-1">段落</p>
</div>
<div>
<p class="after-1">段落</p>
<p class="after-3">段落</p>
</div>
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
+3
/<div[^>]*>([ |\s| ]*)([\s\S]*)<\/div>/ig
でdivを分割して、(ついでに先頭のスペース群をキャッチ)
/<p[^>]*>[^<]+<\/p>([ |\s| ]*)/ig
それをまた分割して、(ついでに後方のスペース群をキャッチ)
それぞれスペースをカウントして<pの後(or class=""内)にクラスを追加する感じでしょうか。
追記:
書き方が悪いのだと思いますがRegExpで取得すると空白が無視されてしまうので未完成ですが、splitやreplaceで処理すれば何とかなると思います。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
checkベストアンサー
+2
String.prototype.replace
String.prototype.replace
の第二引数に関数を指定して分岐処理すれば良いと思います。
<script>
'use strict';
function addClassByStartTag (startTag, token /* [...token] */) {
if (arguments.length < 2) {
return startTag;
}
startTag = /^(<\w+)((\s[^>]*class\s*=\s*")([^"]*)("[^>]*>)|[^>]*>)$/.exec(startTag);
if (startTag[3]) {
var tokens = startTag[4].trim().split(/\s+/);
for (var i = 1, l = arguments.length; i < l; ++i) {
token = arguments[i];
if (tokens.indexOf(token) === -1) {
tokens.push(token);
}
}
return startTag[1] + startTag[3] + tokens.join(' ') + startTag[5];
}
var tokens = [];
for (var i = 1, l = arguments.length; i < l; ++i) {
tokens.push(arguments[i]);
}
return startTag[1] + ' class="' + tokens.join(' ') + '"' + startTag[2];
}
function replaceSample (string) {
var before;
return string.replace(/(<p(?: [^>]*)?>)([^<>]*<\x2Fp>)([^<>]*)|(<[^>]*>)|([^<>]+)/g, function (match, p1, p2, p3, p4, p5) {
if (p1) {
var tokens = [p1], after, length;
if (before) {
tokens.push('before-' + before);
}
after = p3.match(/ /g);
if (after) {
tokens.push('after-' + after.length);
before = after.length;
}
return addClassByStartTag.apply(null, tokens) + p2 + p3;
}
if (p4) {
before = 0;
}
if (p5) {
before = p5.match(/ /g);
before = before ? before.length : 0;
}
return match;
});
}
function handleSubmit (event) {
var elements = event.target.elements;
event.preventDefault();
elements['output'].value = replaceSample(elements['input'].value);
}
</script>
<Form onsubmit="handleSubmit(event);">
<p>
<textarea name="input"><!-- HTMLの形をしていますが実際にはテキスト(文字列)です -->
<!-- beforeはdiv直下のみで後は全てafter -->
<div>
&nbsp;
<p>段落</p>
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
&nbsp;
<p>段落</p>
&nbsp;
&nbsp;
</div>
<div>
&nbsp;
&nbsp;
<p>段落</p>
&nbsp;
&nbsp;
&nbsp;
&nbsp;
<p>段落</p>
&nbsp;
</div>
<div>
<p>段落</p>
&nbsp;
<p>段落</p>
&nbsp;
&nbsp;
&nbsp;
</div>
<!-- div要素をネストする -->
<div>
<div>
<!-- class属性のあるp要素 -->
<p class="hoge">段落</p>
&nbsp;
<p>段落</p>
&nbsp;
&nbsp;
&nbsp;
</div></div><div><!-- テキストノードを挟まない場合 --><p>段落</p>
&nbsp;
<p>段落</p>
&nbsp;
&nbsp;
&nbsp;
</div>
</textarea>
</p>
<p><input type="submit" value="変換"></p>
<p>
<textarea name="output"></textarea>
</p>
</Form>
更新履歴
- 2016/06/12 06:36 連続するp要素の2つ目以降のp要素の before-n が期待通りに動作しなかった不具合を修正。before-n における
の合計算出時に要素を乗り越えて記録していた不具合を修正(今までのサンプルではホワイトスペースノードで数値がクリアされていたので表面化されていませんでした)。
Re: flat さん
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
ごめんなさい,これやってること逆でした… ↓
(後で直します)
<!DOCTYPE html>
<meta charset="UTF-8">
<title>Example</title>
<div>
<p class="before-1 after-6">段落</p>
<p class="after-2">段落</p>
</div>
<div>
<p class="before-2 after-4">段落</p>
<p class="after-1">段落</p>
</div>
<div>
<p class="after-1">段落</p>
<p class="after-3">段落</p>
</div>
<script>
'use strict';
addEventListener('DOMContentLoaded', function () {
Array.prototype.slice.call(document.getElementsByTagName('p')).forEach(function (p) {
var reg = /\b(before|after)-(\d+)\b/g;
var cls = p.getAttribute('class');
var m;
while ((m = reg.exec(cls)) !== null) {
var pos = m[1] === 'before' ? 'beforebegin' : 'afterend';
var txt = new Array(parseInt(m[2]) + 1).join(' ');
p.insertAdjacentHTML(pos, txt);
}
});
});
</script>
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.34%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/06/11 17:05
正規表現が苦手なのでとても勉強になります。
>それぞれスペースをカウントして<pの後(or class=""内)にクラスを追加する
実はここの処理がずっと思いつかなかった事が質問に踏み切った理由だったりします…。
2016/06/11 18:53
2016/06/11 21:03
早速チャレンジします。