NSPredicate的常見(jiàn)使用

轉(zhuǎn)自NSPredicate的使用
版本:iOS13.7

一聘殖、簡(jiǎn)介

給NSPredicate(謂詞)設(shè)定一個(gè)表達(dá)式楔壤,可評(píng)估對(duì)象是否符合該表達(dá)式,也可過(guò)濾出符合表達(dá)式的數(shù)據(jù)(NSArray往踢、NSSet、NSOrderedSet)。
NSPredicate有兩個(gè)子類(lèi),分別是NSComparisonPredicate和NSCompoundPredicate坷虑。
NSComparisonPredicate 比較謂詞,點(diǎn)擊NSComparisonPredicate的使用了解埂奈。
NSCompoundPredicate 復(fù)合謂詞迄损,點(diǎn)擊NSCompoundPredicate的使用了解。

二账磺、NSPredicate的API

//通過(guò)表達(dá)式創(chuàng)建一個(gè)謂詞實(shí)例
//關(guān)于表達(dá)式 詳見(jiàn)(四芹敌、謂語(yǔ)表達(dá)式語(yǔ)法)
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat, ...;
//通過(guò)表達(dá)式創(chuàng)建一個(gè)謂詞實(shí)例
//表達(dá)式中的%@占位符將從arguments中取值,占位符數(shù)量必須小于等于arguments元素的數(shù)量
//詳見(jiàn)說(shuō)明1
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat argumentArray:(nullable NSArray *)arguments;
//通過(guò)表達(dá)式創(chuàng)建一個(gè)謂詞實(shí)例
//表達(dá)式中的%@占位符將從argList中取值垮抗,占位符數(shù)量必須小于等于argList元素的數(shù)量
//詳見(jiàn)說(shuō)明1
+ (NSPredicate *)predicateWithFormat:(NSString *)predicateFormat arguments:(va_list)argList;

//該方法只有macos可用氏捞,暫不說(shuō)明
+ (nullable NSPredicate *)predicateFromMetadataQueryString:(NSString *)queryString;
API_AVAILABLE(macos(10.9)) API_UNAVAILABLE(ios, watchos, tvos)

//創(chuàng)建一個(gè)結(jié)果始終為YES/NO的謂詞實(shí)例
//詳見(jiàn)說(shuō)明2
+ (NSPredicate *)predicateWithValue:(BOOL)value; 

//根據(jù)回調(diào)的返回值來(lái)創(chuàng)建一個(gè)結(jié)果為YES/NO謂詞實(shí)例
//其中回調(diào)的evaluatedObject和bindings分別為evaluateWithObject方法的object和bindings
//詳見(jiàn)例1
+ (NSPredicate*)predicateWithBlock:(BOOL (^)(id _Nullable evaluatedObject, NSDictionary<NSString *, id> * _Nullable bindings))block;

//返回謂詞的表達(dá)式字符串 只讀
//[NSPredicate predicateWithFormat:@"SELF CONTAINS 'world'"]的表達(dá)式為SELF CONTAINS "world"
@property (readonly, copy) NSString *predicateFormat; 

//用常量值代替變量
//即用字典中的鍵值對(duì)替換用$聲明的變量
//詳見(jiàn)說(shuō)明3
- (instancetype)predicateWithSubstitutionVariables:(NSDictionary<NSString *, id> *)variables;  

//評(píng)估對(duì)象是否符合該謂詞
- (BOOL)evaluateWithObject:(nullable id)object;

//評(píng)估對(duì)象是否符合該謂詞
//其中bindings字典中的元素可以代替用$聲明的變量,詳見(jiàn)predicateWithSubstitutionVariables方法的說(shuō)明3
//也可以作為回調(diào)的參數(shù)冒版,詳見(jiàn)predicateWithBlock方法的例1
- (BOOL)evaluateWithObject:(nullable id)object substitutionVariables:(nullable NSDictionary<NSString *, id> *)bindings;

//強(qiáng)制使用已安全解碼的謂詞以進(jìn)行評(píng)估
//當(dāng)使用 NSSecureCoding編碼的NSPredicate對(duì)象在安全解碼時(shí)液茎,是不能被評(píng)估的。
//因?yàn)樵u(píng)估一個(gè)從存檔中取出的predicate是有潛在風(fēng)險(xiǎn)的辞嗡。
//在激活評(píng)估之前豁护,我們應(yīng)該證實(shí)key paths, selectors,和其他細(xì)節(jié)來(lái)確保沒(méi)有錯(cuò)誤或惡意代碼被執(zhí)行。
//一旦我們驗(yàn)證了predicate欲间,我們就可以通過(guò)調(diào)用allowEvaluation來(lái)激活接收器來(lái)評(píng)估楚里。
- (void)allowEvaluation;

說(shuō)明1:以下三種初始化方法的意義相同,最后的生成的表達(dá)式都為SELF CONTAINS "world"

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS 'world'"];
等價(jià)于
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@", @"world"];
等價(jià)于
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@"
                         argumentArray:@[@"world"]];
//若要使用雙引號(hào)" "猎贴,需要加上轉(zhuǎn)義符\
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS \"world\""];

說(shuō)明2:當(dāng)調(diào)用evaluateWithObject時(shí)班缎,無(wú)論傳入的對(duì)象是什么蝴光,只會(huì)返回YES/NO,以下

NSPredicate *predicate = [NSPredicate predicateWithValue:YES];
等價(jià)于
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"TRUEPREDICATE"];

NSPredicate *predicate = [NSPredicate predicateWithValue:NO];
等價(jià)于
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"FALSEPREDICATE"];

說(shuō)明3:輸出的格式字符串為SELF CONTAINS "wor"
實(shí)際上和NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS %@", @"wor"];實(shí)現(xiàn)的效果相同

   NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF CONTAINS $variable"];
   //字典中的key需要和$后面聲明的變量相同达址,可以聲明多個(gè)變量蔑祟,但字典中需要全部包含
   predicate = [predicate predicateWithSubstitutionVariables:@{@"variable":@"wor"}];
   NSLog(@"%@", [predicate predicateFormat]);

 //舉例
   NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSArray * _Nullable >evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
       //通過(guò)回調(diào)的evaluatedObject和bindings來(lái)判斷是否過(guò)濾
       if ([evaluatedObject containsObject:[bindings objectForKey:@"key"]]) {
           return YES;
       } else {
           return NO;
       }
   }];
   BOOL eva = [predicate evaluateWithObject:@[@"1", @"2"] >substitutionVariables:@{@"key":@"2"}];
   NSLog(@"%@", @(eva));
輸出:
1

三、NSPredicate的擴(kuò)展API

@interface NSArray<ObjectType> (NSPredicateSupport)

//將數(shù)組中的每個(gè)元素進(jìn)行評(píng)估沉唠,返回所有符合謂詞的元素的新數(shù)組
- (NSArray<ObjectType> *)filteredArrayUsingPredicate:(NSPredicate *)predicate; 

@end
@interface NSMutableArray<ObjectType> (NSPredicateSupport)

//將數(shù)組中的每個(gè)元素進(jìn)行評(píng)估疆虚,移除所有不符合謂詞的元素
- (void)filterUsingPredicate:(NSPredicate *)predicate; 

@end

filteredArrayUsingPredicate會(huì)返回一個(gè)新數(shù)組,原數(shù)組不會(huì)變化满葛。
filterUsingPredicate會(huì)直接改變?cè)瓟?shù)組的內(nèi)容径簿,如有需要,請(qǐng)先對(duì)原數(shù)組備份嘀韧。
例:

    //選出大于10且小于50的元素
    predicate = [NSPredicate predicateWithFormat:@"SELF > 10 AND SELF < 50"];
    NSArray *array = @[@20, @30, @40, @50, @10, @5];
    NSMutableArray *muta = [array mutableCopy];
    NSLog(@"過(guò)濾前\narray = %@\n muta = %@", array, muta);
    NSArray *array1 = [array filteredArrayUsingPredicate:predicate];
    [muta filterUsingPredicate:predicate];
    NSLog(@"過(guò)濾后\narray = %@\n array1 = %@\n muta = %@", array, array1, muta);
輸出:
過(guò)濾前
array = (
    20,
    30,
    40,
    50,
    10,
    5
)
 muta = (
    20,
    30,
    40,
    50,
    10,
    5
)
過(guò)濾后
array = (
    20,
    30,
    40,
    50,
    10,
    5
)
 array1 = (
    20,
    30,
    40
)
 muta = (
    20,
    30,
    40
)

NSSet篇亭、NSMutableSet、NSOrderedSet锄贷、NSMutableOrderedSet的NSPredicate擴(kuò)展API
功能與NSArray译蒂、NSMutableArray的擴(kuò)展API相同

@interface NSSet<ObjectType> (NSPredicateSupport)
- (NSSet<ObjectType> *)filteredSetUsingPredicate:(NSPredicate *)predicate ;
@end

@interface NSMutableSet<ObjectType> (NSPredicateSupport)
- (void)filterUsingPredicate:(NSPredicate *)predicate ;
@end

@interface NSOrderedSet<ObjectType> (NSPredicateSupport)
- (NSOrderedSet<ObjectType> *)filteredOrderedSetUsingPredicate:(NSPredicate *)p;
@end

@interface NSMutableOrderedSet<ObjectType> (NSPredicateSupport)
- (void)filterUsingPredicate:(NSPredicate *)p;
@end

四、謂語(yǔ)表達(dá)式語(yǔ)法:表達(dá)式字符串并不會(huì)進(jìn)行語(yǔ)義檢測(cè)谊却,必須保證正確性

表達(dá)式語(yǔ)法參考簡(jiǎn)要理解 - NSPredicate

占位符
$:聲明變量柔昼,例如 $variable,詳見(jiàn)說(shuō)明3
%K :屬性名
%@ :屬性值

   NSString *name = @"key1";
   NSString *value = @"23";
   //字典中的鍵為key1的值是否包含"23"
   predicate = [NSPredicate predicateWithFormat:@"key1 CONTAINS %@", value];
   NSLog(@"%@", [predicate predicateFormat]);
   predicate = [NSPredicate predicateWithFormat:@"%K CONTAINS %@", name, value];
   NSLog(@"%@", [predicate predicateFormat]);
   eva = [predicate evaluateWithObject:@{@"key1":@"value12345"}];
   NSLog(@"%@", @(eva));
輸出:
key1 CONTAINS "23"
key1 CONTAINS "23"
1

可以看到兩種初始化的表達(dá)式字符串都是key1 CONTAINS "23"
%@表示的是"23"這個(gè)帶雙引號(hào)的值炎辨,%K表示的是不帶引號(hào)key1
%K好像不能表示關(guān)鍵字岳锁,如SELF等

基本比較運(yùn)算
=、== 左邊是否等于右邊
=蹦魔、 => 左邊是否大于或等于右邊
<=激率、=< 左邊是否小于或等于右邊
左邊是否大于右邊
< 左邊是否小于右邊
!=、<> 左邊是否不等于右邊
BETWEEN 左邊的值是否在區(qū)間內(nèi)(包含邊界數(shù)值)

例如@"SELF BETWEEN {10勿决, 50}"等價(jià)于@"SELF >= 10 AND SELF <= 50"

布爾值謂語(yǔ)
TRUEPREDICATE 始終返回真
FALSEPREDICATE 始終返回假

例如[NSPredicate predicateWithValue:YES]的表達(dá)式實(shí)際上就是TRUEPREDICATE

基本復(fù)合謂語(yǔ)
AND乒躺、&& 與
OR、|| 或
NOT低缩、!: 非

例如[NSPredicate predicateWithFormat:@"SELF > 10 AND SELF < 50"]表示大于10并且小于50
[NSPredicate predicateWithFormat:@"SELF > 10 or SELF < 5"]表示大于10或者小于5
[NSPredicate predicateWithFormat:@"NOT SELF > 10"]表示不大于10

字符串比較
BEGINSWITH 左邊字符串是否以右邊字符串開(kāi)始
ENDSWITH 左邊字符串是否以右邊字符串結(jié)束
CONTAINS 左邊字符串內(nèi)容是否包含右邊字符串
LIKE 左邊字符串是否等于右邊字符串
MATCHES 左邊字符串是否符合右邊的正則表達(dá)式

例如[NSPredicate predicateWithFormat:@"SELF BEGINSWITH 'world'"]表示worldxxx這種字符串嘉冒,xxx表示0個(gè)或多個(gè)字符

[NSPredicate predicateWithFormat:@"SELF ENDSWITH 'world'"]表示xxxworld這種字符串
[NSPredicate predicateWithFormat:@"SELF CONTAINS 'world'"]表示xxxworldxxx這種字符串
[NSPredicate predicateWithFormat:@"SELF LIKE 'world'"]表示字符串world
[NSPredicate predicateWithFormat:@"SELF MATCHES '^1[3|4|5|7|8][0-9]{9}$'"]表示符合手機(jī)號(hào)正則表達(dá)式的字符串

可以在關(guān)鍵字后面加在[cd],c表示忽略大小寫(xiě)咆繁,即CAFE與cafe為相同字符串讳推;d表示忽略讀音,即café與cafe為相同字符串玩般。
例如[NSPredicate predicateWithFormat:@"SELF CONTAINS[cd] 'CAfé'"]與[NSPredicate predicateWithFormat:@"SELF CONTAINS 'cafe'"]功能相同

LIKE后面可以使用通配符?和银觅,但不能在%@占位符的值中使用
?表示指代一個(gè)字符 表示指代0個(gè)或多個(gè)字符
例如[NSPredicate predicateWithFormat:@"SELF LIKE '?world
'"]表示aworldaaa這種字符串
[NSPredicate predicateWithFormat:@"SELF LIKE %@", @"?world
"],這種是錯(cuò)誤寫(xiě)法坏为,只能識(shí)別字符串?world究驴,?在此處不能當(dāng)成通配符

集合操作
ANY镊绪、SOME 是否對(duì)象的元素至少有一個(gè)滿(mǎn)足后面的表達(dá)式
ALL 是否對(duì)象的元素全都滿(mǎn)足后面的表達(dá)式
NONE 是否對(duì)象的元素全都不滿(mǎn)足后面的表達(dá)式
上面的三種,評(píng)估的對(duì)象(evaluateWithObject的參數(shù))必須是NSArray或NSSet

例如[NSPredicate predicateWithFormat:@"ANY SELF CONTAINS[cd] 'cafe'"]
表示@[@"cafe1", @"c afe2", @"c afe3"]這種數(shù)組
[NSPredicate predicateWithFormat:@"ALL SELF CONTAINS[cd] 'cafe'"]
表示@[@"cafe1", @"cafe2", @"cafe3"]這種數(shù)組
[NSPredicate predicateWithFormat:@"NONE SELF CONTAINS[cd] 'cafe'"]
表示@[@"c afe1", @"c afe2", @"c afe3"]這種數(shù)組

IN 左邊元素是否在右邊元素集合出現(xiàn)洒忧,集合可以是NSArray蝴韭、NSSet、NSDictionary熙侍,如果是NSDictionary榄鉴,將取其所有value的值的數(shù)組。

例:
  //cafe是否在集合中
   predicate = [NSPredicate predicateWithFormat:@"SELF IN[cd] {'cafe', 'apple', 'tea'}"];
  eva = [predicate evaluateWithObject:@"cafe"];
   NSLog(@"%@", @(eva));
輸出:1

當(dāng)evaluateWithObject的參數(shù)為NSArray蛉抓、NSSet庆尘、NSDictionary時(shí),可使用以下寫(xiě)法表示單個(gè)元素芝雪。
SELF[index],表示取對(duì)應(yīng)索引的元素综苔,index不要越界
SELF[FIRST]惩系,表示第一個(gè)元素
SELF[LAST],表示最后一個(gè)元素
SELF[SIZE]如筛,表示元素的個(gè)數(shù)

   //數(shù)組的第0個(gè)元素是否在集合中
   predicate = [NSPredicate predicateWithFormat:@"SELF[0] IN[cd] {'cafe', 'apple', 'tea'}"];
   eva = [predicate evaluateWithObject:@[@"cafe", @"cafe1"]];
   NSLog(@"%@", @(eva));
輸出:1

若為NSDictionary堡牡,可使用
SELF['key']或SELF.key或key(即不要前面的SELF),表示對(duì)應(yīng)key的元素

   //字典key為key1的值是否在集合中
   predicate = [NSPredicate predicateWithFormat:@"SELF.key1 IN[cd] {'cafe', 'apple', 'tea'}"];
   eva = [predicate evaluateWithObject:@{@"key1":@"apple"}];
   NSLog(@"%@", @(eva));
輸出:1

字面量語(yǔ)義
FALSE杨刨、NO 邏輯假
TRUE晤柄、YES 邏輯真

   predicate = [NSPredicate predicateWithFormat:@"SELF = TRUE"];
   eva = [predicate evaluateWithObject:@(YES)];

五、應(yīng)用

//PredicateModel的.h文件
@interface PredicateModel : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *adress;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, strong) PredicateModel *subModel;

@end
//PredicateModel的.m文件
@implementation PredicateModel

- (NSString *)description {
    return [NSString stringWithFormat:@"name = %@ adress = %@ age = %ld subModel = (%@)",
           self.name, self.adress, self.age, self.subModel?:@"empty"];
}

@end
    NSArray *names = @[@"aa", @"bb", @"cc"];
    NSMutableArray *models = [NSMutableArray array];
    for (NSInteger i = 0; i < 6; i++) {
        PredicateModel *model = [[PredicateModel alloc] init];
        model.name = [NSString stringWithFormat:@"%@", names[i%3]];
        model.adress = [NSString stringWithFormat:@"adress%ld", i];
        model.age = 10+random()%5;
        if (i%2 == 1) {
            //1 3 5時(shí)將上個(gè)model添加成subModel
            model.subModel = [models lastObject];
        }
        [models addObject:model];
    }
    NSLog(@"models = %@", models);
    //查詢(xún)age>12且name為aa或cc的model
    NSPredicate *modelPredicate = [NSPredicate predicateWithFormat:@"SELF.age > 12 AND (name = %@ OR name = %@)", names.firstObject, names.lastObject];
    NSArray *result = [models filteredArrayUsingPredicate:modelPredicate];
    NSLog(@"result = %@", result);
    //二級(jí)查詢(xún) 查詢(xún)subModel存在并且subModel的age>12的model
    modelPredicate = [NSPredicate predicateWithFormat:@"subModel != NULL AND subModel.age >12"];
    result = [models filteredArrayUsingPredicate:modelPredicate];
    NSLog(@"result = %@", result);
輸出:
models = (
    "name = aa adress = adress0 age = 13 subModel = (empty)",
    "name = bb adress = adress1 age = 11 subModel = (name = aa adress = adress0 age = 13 subModel = (empty))",
    "name = cc adress = adress2 age = 12 subModel = (empty)",
    "name = aa adress = adress3 age = 10 subModel = (name = cc adress = adress2 age = 12 subModel = (empty))",
    "name = bb adress = adress4 age = 13 subModel = (empty)",
    "name = cc adress = adress5 age = 10 subModel = (name = bb adress = adress4 age = 13 subModel = (empty))"
)
result = (
    "name = aa adress = adress0 age = 13 subModel = (empty)"
)
result = (
    "name = bb adress = adress1 age = 11 subModel = (name = aa adress = adress0 age = 13 subModel = (empty))",
    "name = cc adress = adress5 age = 10 subModel = (name = bb adress = adress4 age = 13 subModel = (empty))"
)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末妖胀,一起剝皮案震驚了整個(gè)濱河市芥颈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赚抡,老刑警劉巖爬坑,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涂臣,居然都是意外死亡盾计,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)赁遗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)署辉,“玉大人,你說(shuō)我怎么就攤上這事岩四】蕹ⅲ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵剖煌,是天一觀的道長(zhǎng)刚夺。 經(jīng)常有香客問(wèn)我献丑,道長(zhǎng),這世上最難降的妖魔是什么侠姑? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任创橄,我火速辦了婚禮,結(jié)果婚禮上莽红,老公的妹妹穿的比我還像新娘妥畏。我一直安慰自己,他們只是感情好安吁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布醉蚁。 她就那樣靜靜地躺著,像睡著了一般鬼店。 火紅的嫁衣襯著肌膚如雪网棍。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天妇智,我揣著相機(jī)與錄音滥玷,去河邊找鬼。 笑死巍棱,一個(gè)胖子當(dāng)著我的面吹牛惑畴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播航徙,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼如贷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了到踏?” 一聲冷哼從身側(cè)響起杠袱,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窝稿,沒(méi)想到半個(gè)月后霞掺,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡讹躯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年菩彬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潮梯。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡骗灶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秉馏,到底是詐尸還是另有隱情耙旦,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布萝究,位于F島的核電站免都,受9級(jí)特大地震影響锉罐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绕娘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一脓规、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧险领,春花似錦侨舆、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至脐湾,卻和暖如春臭笆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背秤掌。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工愁铺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人机杜。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓帜讲,卻偏偏與公主長(zhǎng)得像衅谷,于是被迫代替她去往敵國(guó)和親椒拗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容