こんにちは!この質問はかなり長いので、必ず最初に座ってください :)
コードのある時点で、ユーザーから文字列を取得し、その文字列を分析します。分析とは、すべての文字を調べて、ユーザーが NSPredicateEditor で設定した述語と照合することを意味します。述語は、次のようにプログラム的に設定されます。
NSArray* keyPaths = [NSArray arrayWithObjects:
[NSExpression expressionForKeyPath: @"Character"],
[NSExpression expressionForKeyPath: @"Character Before"],
[NSExpression expressionForKeyPath: @"Character After"],
nil];
// -----------------------------------------
NSArray* constants = [NSArray arrayWithObjects:
[NSExpression expressionForConstantValue: @"Any letter"],
[NSExpression expressionForConstantValue: @"Letter (uppercase)"],
[NSExpression expressionForConstantValue: @"Letter (lowercase)"],
[NSExpression expressionForConstantValue: @"Number"],
[NSExpression expressionForConstantValue: @"Alphanumerical"],
[NSExpression expressionForConstantValue: @"Ponctuation Mark"],
nil];
// -----------------------------------------
NSArray* compoundTypes = [NSArray arrayWithObjects:
[NSNumber numberWithInteger: NSNotPredicateType],
[NSNumber numberWithInteger: NSAndPredicateType],
[NSNumber numberWithInteger: NSOrPredicateType],
nil];
// -----------------------------------------
NSArray* operatorsA = [NSArray arrayWithObjects:
[NSNumber numberWithInteger: NSEqualToPredicateOperatorType],
[NSNumber numberWithInteger: NSNotEqualToPredicateOperatorType],
nil];
NSArray* operatorsB = [NSArray arrayWithObjects:
[NSNumber numberWithInteger: NSInPredicateOperatorType],
nil];
// -----------------------------------------
NSPredicateEditorRowTemplate* template1 = [[NSPredicateEditorRowTemplate alloc] initWithLeftExpressions: keyPaths
rightExpressions: constants
modifier: NSDirectPredicateModifier
operators: operatorsA
options: 0];
NSPredicateEditorRowTemplate* template2 = [[NSPredicateEditorRowTemplate alloc] initWithLeftExpressions: keyPaths
rightExpressionAttributeType: NSStringAttributeType
modifier: NSDirectPredicateModifier
operators: operatorsB
options: 0];
NSPredicateEditorRowTemplate* compound = [[NSPredicateEditorRowTemplate alloc] initWithCompoundTypes: compoundTypes];
// -----------------------------------------
NSArray* rowTemplates = [NSArray arrayWithObjects: template1, template2, compound, nil];
[myPredicateEditor setRowTemplates: rowTemplates];
3 つのキーパスと、それらを比較できるいくつかの定数があることがわかります。文字列を分析するとき、私は基本的に疑似コードでこれを行いたい:
originalString = [string from NSTextView]
for (char in originalString)
bChar = [character before char]
aChar = [character after char]
predicate = [predicate from myPredicateEditor]
// using predicate - problem!
result = [evaluate predicate with:
bChar somehow 'linked' to keypath 'Character Before'
char 'linked' to 'Character'
aChar 'linked' to 'Character After' // These values change, of course
and also:
constant "All letters" as "abc...WXYZ"
constant "Numbers" as "0123456789"
etc for all other constants set up // These don't
]
if (result) then do something with char, bChar and aChar
私の問題が基本的にどこにあるかを見ることができます:
「文字の前/後」は、スペースのためにキーパスにすることはできませんが、ユーザーにとってより美しいので、そのままにしておきたいです (代わりに「文字の前」として何かがあると想像してください...)
「Numbers」などの定数は、実際には「0123456789」などの文字列を表しますが、ユーザーにも表示できません
この問題の回避策を見つけることができましたが、現在はすべてのキャラクターで機能するわけではなく、非常に非効率的です (少なくとも私の意見では)。私がしていることは、述語から述語形式を取得し、置き換える必要があるものを置き換え、代わりにその新しい形式を評価することです。これを説明する実際のコードについては、次のとおりです。
#define kPredicateSubstitutionsDict [NSDictionary dictionaryWithObjectsAndKeys: \
@"IN 'abcdefghijklmnopqrstuvwxyz'", @"== \"Letter (lowercase)\"", \
@"IN 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'", @"== \"Letter (uppercase)\"", \
@"IN 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'", @"== \"Any letter\"", \
@"IN '1234567890'", @"== \"Number\"", \
@"IN 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'", @"== \"Alphanumerical\"", \
@"IN ',.;:!?'", @"== \"Ponctuation Mark\"", \
\
@"MATCHES '[^a-z]'" , @"!= \"Letter (lowercase)\"", \
@"MATCHES '[^A-Z]'" , @"!= \"Letter (uppercase)\"", \
@"MATCHES '[^a-zA-Z]'" , @"!= \"Any letter\"", \
@"MATCHES '[^0-9]'" , @"!= \"Number\"", \
@"MATCHES '[^a-zA-Z0-9]'" , @"!= \"Alphanumerical\"", \
@"MATCHES '[^,\.;:!\?]'" , @"!= \"Ponctuation Mark\"", \
\
nil]
// NSPredicate* predicate is setup in another place
// NSString* originalString is also setup in another place
NSString* predFormat = [predicate predicateFormat];
for (NSString* key in [kPredicateSubstitutionsDict allKeys]) {
prefFormat = [predFormat stringByReplacingOccurrencesOfString: key withString: [kPredicateSubstitutionsDict objectForKey: key]];
}
for (NSInteger i = 0; i < [originalString length]; i++) {
NSString* charString = [originalString substringWithRange: NSMakeRange(i, 1)];
NSString* bfString;
NSString* afString;
if (i == 0) {
bfString = @"";
}
else {
bfString = [originalString substringWithRange: NSMakeRange(i - 1, 1)];
}
if (i == [originalString length] - 1) {
afString = @"";
}
else {
afString = [originalString substringWithRange: NSMakeRange(i + 1, 1)];
}
predFormat = [predFormat stringByReplacingOccurrencesOfString: @"Character Before" withString: [NSString stringWithFormat: @"\"%@\"", bfString]];
predFormat = [predFormat stringByReplacingOccurrencesOfString: @"Character After" withString: [NSString stringWithFormat: @"\"%@\"", afString]];
predFormat = [predFormat stringByReplacingOccurrencesOfString: @"Character" withString: [NSString stringWithFormat: @"\"%@\"", charString]];
NSPredicate* newPred = [NSPredicate predicateWithFormat: predFormat];
if ([newPred evaluateWithObject: self]) { // self just so I give it something (nothing is actually gotten from self)
// if predicate evaluates to true, then do something exciting!
}
}
ですから、これは私がやっていることの単純化されたバージョンです。タイプミスが見られる場合は、おそらく私のコードには含まれていません。
要約する:
- ユーザーが多くの文字に対して行う述語を評価し、可能な限り効率的にしようとしながら、かなり変更する必要があります
私のアプローチで見つけた問題は次のとおりです。
- 全然きれいじゃないと思う
- すべてのケースで機能するという保証はありません (文字の 1 つが改行/入力文字の場合、述語は形式を理解できないというエラーを発生させます)。
それはすべての人々です!ここまで読んでくれてありがとう。この混乱を解決するとき、あなたの神があなたと共にありますように!
編集:関連することを明確にするために、この問題の引き金と思われるのは、述語エディターをセットアップする最初の時点で、名前を持つ1つの定数を定義できないという事実であると付け加えます(ユーザーに表示されます) ) およびその定数を表し、述語形式に挿入される値。キーパスについても同じです。1 つの表示名と、述語 ($VAR など) の var 文字列である 1 つの値を使用できれば、すべての問題が解決されます。これが可能であれば、方法を教えてください。それが不可能な場合は、私が説明する他の問題に集中してください。