次のことを行う関数を作成しようとしています。
コード入力が "(a 1 2 (b 3 4 5 (c 6) |7) 8 9)" であると仮定すると、パイプ | 記号はカーソルの位置、
関数は次を返します: カーソルのスコープ内にあるコードを表す文字列 "b 3 4 5 (c 6) 7"
入力に対する文字列の開始インデックスを表す int 8
入力に対する文字列の終了インデックスを表す int 30
まさにそれを返す作業コードがすでにあります。ただし、問題は、コンテキストを追跡しながらコメントを無視することにあります (たとえば、文字列リテラル、独自のリテラル区切り記号など)。
コンテキストを追跡するコードは次のとおりです。
public static void applyContext(Context context, String s, String snext, String sprev) {
if (s.equals("\"")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = true;
} else if (context.context == Context.Contexts.STRING && context.stringDelimiterIsADoubleQuote && !sprev.equals("\\"))
context.context = Context.Contexts.MAIN;
} else if (s.equals("\'")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = false;
} else if (context.context == Context.Contexts.STRING && !context.stringDelimiterIsADoubleQuote && !sprev.equals("\""))
context.context = Context.Contexts.MAIN;
} else if (s.equals("/") && snext.equals("/")) {
if (context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.COMMENT;
} else if (s.equals("\n")) {
if(context.context == Context.Contexts.COMMENT)
context.context = Context.Contexts.MAIN;
}
else if (s.equals("\\")) {
if(context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.PATTERN;
else if(context.context == Context.Contexts.PATTERN)
context.context = Context.Contexts.MAIN;
}
}
まず、上記の関数を次のように使用します。
String sampleCode = "(a b "cdef" g \c4 bb2 eb4 g4v0.75\)";
Context c = new Context(Context.Contexts.MAIN);
for(int i = 0; i < sampleCode.length(); i++) {
String s = String.valueOf(sampleCode.charAt(i));
String snext = *nullcheck* ? String.valueOf(sampleCode.charAt(i + 1)) : "";
String sprev = *nullcheck* ? String.valueOf(sampleCode.charAt(i - 1)) : "";
applyContext(c, s, snext, sprev);
if(c.context == blahlbah) doBlah();
}
第二に、説明の上部に記載されている機能を実行する現在の方法は(疑似コードで)これであるため、これを前方と後方の両方で使用します。
function returnCodeInScopeOfCursor(theWholeCode::String, cursorIndex::int) {
var depthOfCodeAtCursorPosition::int = getDepth(theWholeCode, cursorIndex);
Context c = new Context(getContextAt(theWholeCode, cursorIndex));
var currDepth::int = depthOfCodeAtCursorPosition;
var startIndex::int, endIndex::int;
for(i = cursorIndex; i >= 0; i--) {//going backwards
s = .....
snext = ......
sprev = ......
applyContext(c, s, snext, sprev);
if(c.context == Context.MAIN) {
if s = "(" then currDepth --;
if s = ")" then currDepth ++;
}
when currDepth < depthOfCodeAtCursorPosition
startIndex = i + 1;
break;
}
currDepth = depthOfCodeAtCursorPosition;//reset
for(i = cursorIndex; i < theWholeCode.length; i++) {//going forwards
s = ...
snex......
sprev.....
applyContext(c, s, snext, sprev);
if(c.context == Context.MAIN) {
if s = "(" then currDepth ++;
if s = ")" then currDepth --;
}
when currDepth < depthOfCodeAtCursorPosition
endIndex = i - 1;
break;
}
var returnedStr = theWholeCode->from startIndex->to endIndex
return new IndexedCode(returnedStr, startIndex, endIndex);
ご覧のとおり、この関数は順方向と逆方向の両方で機能します。または、少なくともそのほとんど。唯一の問題は、この関数を逆方向に使用すると、コメント (標準の ECMA 二重スラッシュ "//" で示される) の適切なスキャンがうまくいかないことです。
リバース コンテキスト アプリケーション用に別の関数を作成し、すべての行で二重スラッシュを再帰的にチェックし、その '//' の後のすべてを COMMENT にする場合 (または、関数の使用方向では、 //より前のすべて)、これを音楽のライブコーディング環境として使用したいので、処理時間がかかりすぎます。
また、そのメソッドを実行しようとする前にコメントを削除することはreturnCodeInScopeOfCursor
実行できない場合があります...コードのインデックスとそうでないものを追跡する必要があるためです。コメントを削除すると、すべてのコード位置に大きな混乱が生じ、どこで何を正確に何文字削除したかなどを追跡することになります....私が使用しているテキスト領域入力 GUI (RichTextFX ) は Line-Char 追跡をサポートしていないため、すべてが char インデックスのみを使用して追跡されるため、問題が発生します...
だから...私は現在のコードをどうするかについて完全に当惑しています。ヘルプ、提案、アドバイスなど...大歓迎です。