質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

2053閲覧

特定の文字列Aの間にある指定した文字列BをカウントしてAに追加

flat

総合スコア617

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2016/06/11 05:15

編集2016/06/11 08:14

HTMLの形をしたテキスト(すべて文字列なのでDOMやNodeなどは存在しない)にあるnbspをカウントしてp要素に該当する文字列にクラスとして追加したいのですが、この様に文字列の部分的な処理を連続して行うにはどうしたら良いでしょうか?

ちなみに、この処理はMeryというテキストエディタのマクロとして利用するつもりなのですが、マクロ機能でJavaScriptがそのまま使える様なので、テキストエディタの事は特に考慮せず、普通のJavaScriptの質問として見て頂いて構いません。

<!-- 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>

↑を↓にしたい。

<!-- HTMLの形をしていますが実際にはテキスト(文字列)です --> <!-- beforeはdiv直下のみで後は全てafter --> <div> &nbsp; <p class="before-1 after-6">段落</p> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <p class="after-2">段落</p> &nbsp; &nbsp; </div> <div> &nbsp; &nbsp; <p class="before-2 after-4">段落</p> &nbsp; &nbsp; &nbsp; &nbsp; <p class="after-1">段落</p> &nbsp; </div> <div> <p class="after-1">段落</p> &nbsp; <p class="after-3">段落</p> &nbsp; &nbsp; &nbsp; </div>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

/<div[^>]*>([&nbsp;|\s| ]*)([\s\S]*)<\/div>/ig ```でdivを分割して、(ついでに先頭のスペース群をキャッチ)

/<p[^>]>[^<]+</p>([ |\s| ])/ig

それぞれスペースをカウントして<pの後(or class=""内)にクラスを追加する感じでしょうか。 --- **追記:** 書き方が悪いのだと思いますがRegExpで取得すると空白が無視されてしまうので未完成ですが、splitやreplaceで処理すれば何とかなると思います。 **動くサンプル:**[https://jsfiddle.net/mLwwq58g/1/](https://jsfiddle.net/mLwwq58g/1/)

投稿2016/06/11 07:28

編集2016/06/11 09:52
kei344

総合スコア69407

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

flat

2016/06/11 08:05

回答して下さりありがとうございます。 正規表現が苦手なのでとても勉強になります。 >それぞれスペースをカウントして<pの後(or class=""内)にクラスを追加する 実はここの処理がずっと思いつかなかった事が質問に踏み切った理由だったりします…。
kei344

2016/06/11 09:53

少しコードを書いてみました。正直未完成なのですが、方向性はわかるかと思います。(回答に追記しています)
flat

2016/06/11 12:03

サンプルを提示して下さりありがとうございます。 早速チャレンジします。
guest

0

ベストアンサー

String.prototype.replace

String.prototype.replace の第二引数に関数を指定して分岐処理すれば良いと思います。

JavaScript

1<script> 2'use strict'; 3function addClassByStartTag (startTag, token /* [...token] */) { 4 if (arguments.length < 2) { 5 return startTag; 6 } 7 8 startTag = /^(<\w+)((\s[^>]*class\s*=\s*")([^"]*)("[^>]*>)|[^>]*>)$/.exec(startTag); 9 10 if (startTag[3]) { 11 var tokens = startTag[4].trim().split(/\s+/); 12 13 for (var i = 1, l = arguments.length; i < l; ++i) { 14 token = arguments[i]; 15 16 if (tokens.indexOf(token) === -1) { 17 tokens.push(token); 18 } 19 } 20 21 return startTag[1] + startTag[3] + tokens.join(' ') + startTag[5]; 22 } 23 24 var tokens = []; 25 26 for (var i = 1, l = arguments.length; i < l; ++i) { 27 tokens.push(arguments[i]); 28 } 29 30 return startTag[1] + ' class="' + tokens.join(' ') + '"' + startTag[2]; 31} 32 33function replaceSample (string) { 34 var before; 35 36 return string.replace(/(<p(?: [^>]*)?>)([^<>]*<\x2Fp>)([^<>]*)|(<[^>]*>)|([^<>]+)/g, function (match, p1, p2, p3, p4, p5) { 37 if (p1) { 38 var tokens = [p1], after, length; 39 40 if (before) { 41 tokens.push('before-' + before); 42 } 43 44 after = p3.match(/&nbsp;/g); 45 46 if (after) { 47 tokens.push('after-' + after.length); 48 before = after.length; 49 } 50 51 return addClassByStartTag.apply(null, tokens) + p2 + p3; 52 } 53 54 if (p4) { 55 before = 0; 56 } 57 58 if (p5) { 59 before = p5.match(/&nbsp;/g); 60 before = before ? before.length : 0; 61 } 62 63 return match; 64 }); 65} 66 67function handleSubmit (event) { 68 var elements = event.target.elements; 69 70 event.preventDefault(); 71 elements['output'].value = replaceSample(elements['input'].value); 72} 73</script> 74 75<Form onsubmit="handleSubmit(event);"> 76<p> 77<textarea name="input">&lt;!-- HTMLの形をしていますが実際にはテキスト(文字列)です --&gt; 78&lt;!-- beforeはdiv直下のみで後は全てafter --&gt; 79&lt;div&gt; 80&amp;nbsp; 81&lt;p&gt;段落&lt;/p&gt; 82&amp;nbsp; 83&amp;nbsp; 84&amp;nbsp; 85&amp;nbsp; 86&amp;nbsp; 87&amp;nbsp; 88&lt;p&gt;段落&lt;/p&gt; 89&amp;nbsp; 90&amp;nbsp; 91&lt;/div&gt; 92 93&lt;div&gt; 94&amp;nbsp; 95&amp;nbsp; 96&lt;p&gt;段落&lt;/p&gt; 97&amp;nbsp; 98&amp;nbsp; 99&amp;nbsp; 100&amp;nbsp; 101&lt;p&gt;段落&lt;/p&gt; 102&amp;nbsp; 103&lt;/div&gt; 104 105&lt;div&gt; 106&lt;p&gt;段落&lt;/p&gt; 107&amp;nbsp; 108&lt;p&gt;段落&lt;/p&gt; 109&amp;nbsp; 110&amp;nbsp; 111&amp;nbsp; 112&lt;/div&gt; 113 114&lt;!-- div要素をネストする --&gt; 115&lt;div&gt; 116&lt;div&gt; 117&lt;!-- class属性のあるp要素 --&gt; 118&lt;p class="hoge"&gt;段落&lt;/p&gt; 119&amp;nbsp; 120&lt;p&gt;段落&lt;/p&gt; 121&amp;nbsp; 122&amp;nbsp; 123&amp;nbsp; 124&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;!-- テキストノードを挟まない場合 --&gt;&lt;p&gt;段落&lt;/p&gt; 125&amp;nbsp; 126&lt;p&gt;段落&lt;/p&gt; 127&amp;nbsp; 128&amp;nbsp; 129&amp;nbsp; 130&lt;/div&gt; 131</textarea> 132</p> 133<p><input type="submit" value="変換"></p> 134<p> 135<textarea name="output"></textarea> 136</p> 137</Form>

更新履歴

  • 2016/06/12 06:36 連続するp要素の2つ目以降のp要素の before-n が期待通りに動作しなかった不具合を修正。before-n における &nbsp; の合計算出時に要素を乗り越えて記録していた不具合を修正(今までのサンプルではホワイトスペースノードで数値がクリアされていたので表面化されていませんでした)。

Re: flat さん

投稿2016/06/11 12:12

編集2016/06/11 21:44
think49

総合スコア18164

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

flat

2016/06/11 13:22 編集

回答して下さりありがとうございます。 提示して下さったコードは完璧でした。 しかし、どうやらMeryはJavaScriptをそのまま実行できるのではなく、JavaScriptに準拠した仕様という形になっていて String.prototype.replace がサポートされていませんでした…。 これ以上はJavaScriptというよりはMeryが主体の質問になってしまいそうなので、この質問は終了させます。 後は皆さんの回答を参考に試行錯誤してみようと思います。
flat

2016/06/11 17:42 編集

replaceがサポートされていないというのは私の勘違いでした。 また、一部意図した通りに置換されないようです。 具体的にはdiv内の2つ目以降のp要素にも同じbefore-xが追加されていってしまいます。 これを改善するには「div内の一番最初のp要素かどうか」という条件を判定できるようにしなければいけないと思うのですが、replaceSample()内の正規表現を変更する事でこれに対応出来るでしょうか…?
think49

2016/06/11 21:42

修正しました。 正規表現とは関係ない部分でのバグなのでこのコードがどう動いているのか、を一つ一つ追ってみてください。
flat

2016/06/12 05:48

修正して下さりありがとうございます。 修正前 次の p4(before部分の&nbsp;) をキャッチしてカウントするまで before の数値がクリアされていなかった 修正後 before に手前のp要素の after の数値を代入して実質的に正常な数値にした上で、念の為にdiv要素をキャッチしたときに before の数値をクリア コードを読み解く力が自分にはまだまだ不足していると実感したと同時にすごく勉強になりました。
guest

0

ごめんなさい,これやってること逆でした… ↓
(後で直します)

html

1<!DOCTYPE html> 2<meta charset="UTF-8"> 3<title>Example</title> 4 5<div> 6 <p class="before-1 after-6">段落</p> 7 <p class="after-2">段落</p> 8</div> 9<div> 10 <p class="before-2 after-4">段落</p> 11 <p class="after-1">段落</p> 12</div> 13<div> 14 <p class="after-1">段落</p> 15 <p class="after-3">段落</p> 16</div> 17 18<script> 19'use strict'; 20 21addEventListener('DOMContentLoaded', function () { 22 Array.prototype.slice.call(document.getElementsByTagName('p')).forEach(function (p) { 23 var reg = /\b(before|after)-(\d+)\b/g; 24 var cls = p.getAttribute('class'); 25 var m; 26 while ((m = reg.exec(cls)) !== null) { 27 var pos = m[1] === 'before' ? 'beforebegin' : 'afterend'; 28 var txt = new Array(parseInt(m[2]) + 1).join('&nbsp;'); 29 p.insertAdjacentHTML(pos, txt); 30 } 31 }); 32}); 33</script>

イメージ説明

投稿2016/06/11 07:40

編集2016/06/11 07:48
mpyw

総合スコア5223

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

flat

2016/06/11 08:06

回答して下さりありがとうございます。 質問にあるコードなのですが、HTMLの形をしてはいるものの実際にはテキストなのです。 私の質問内容が分かりにくいので書き直します。
mpyw

2016/06/11 08:16

処理系はNode.jsではなくフロントエンドですか?
mpyw

2016/06/11 08:20 編集

なるほどMeryですか.ElectronベースのAtomであれば無理して正規表現で頑張らなくてもDOMParserが使えるのですが,Meryはちょっと怪しいですね… http://caniuse.com/#search=DOMParser
flat

2016/06/11 08:58

やはりDOMとして扱えると便利ですね…。 Atomも利用してはいるのですが、テキストエディタとしては動作が遅いので、ちょっとした編集をしたい時には使いにくいのが難点です…。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問