Go语言基础05——异常、正则、字符串、json、文本文件处理

异常

Go语言引入了一个关于错误处理的标准模式,即error接口,它是Go语言内建的接口类型

package main

import "fmt"
import "errors"

func MyDiv(a, b int) (res int, err error) {
    if b == 0 {
        err = errors.New("除数不能为0")
        return
    }
    res = a / b
    return

}

func testa() {
    fmt.Println("aaaaaaaaaaa")
}
func testb() {
    panic("this is a pinic in testb.")
    fmt.Println("bbbbbbbbbbb")
}
func testc() {
    fmt.Println("ccccccccccc")
}
func testd() {
    arr := make([]int, 10)
    arr[10] = 10
}

func teste() {

    defer func() {
        if err := recover(); err != nil {
            fmt.Println("err in defer :", err) //err in defer : runtime error: index out of range
        }
    }()

    arr := make([]int, 10)
    arr[10] = 10
}
func main() {

    fmt.Println("异常演示案例")

    // 1. error接口的使用
    err1 := fmt.Errorf("%s", "this is normal error1")
    err2 := errors.New("this is normal error2")

    fmt.Println("error2:", err1) //this is normal error1
    fmt.Println("error2:", err2) //this is normal error2

    // 2. error接口的应用
    //res, err := MyDiv(10, 3) //res: 3
    res, err := MyDiv(10, 0) //error: 除数不能为0
    if err != nil {
        fmt.Println("error:", err)
    } else {
        fmt.Println("res:", res)
    }

    fmt.Println("---------------------")
    // 3.1 显式调用panic函数
    testa()
    //testb()
    testc()

    // aaaaaaaaaaa
    // panic: this is a pinic in testb.
    // goroutine 1 [running]:

    // 3.2 数组越界导致panic
    fmt.Println("---------------------")
    //testd() //panic: runtime error: index out of range

    // 4. recover使用
    // 运行时panic异常一旦被引发就会导致程序崩溃。这当然不是我们愿意看到的,因为谁也不能保证程序不会发生任何运行时错误。
    //不过,Go语言为我们提供了专用于“拦截”运行时panic的内建函数——recover。它可以是当前的程序从运行时panic的状态中恢复并重新获得流程控制权。

    //注意:recover只有在defer调用的函数中有效

    //  如果调用了内置函数recover,并且定义该defer语句的函数发生了panic异常,recover会使程序从panic中恢复,并返回panic value。
    //导致panic异常的函数不会继续运行,但能正常返回。在未发生panic时调用recover,recover会返回nil。

    testa()
    teste() //err in defer : runtime error: index out of range
    testc()

}

字符串处理

字符串在开发中经常用到,包括用户的输入,数据库读取的数据等,我们经常需要对字符串进行分割、连接、转换等操作,我们可以通过Go标准库中的strings和strconv两个包中的函数进行相应的操作。
下面这些函数来自于strings包,这里介绍一些我平常经常用到的函数,更详细的请参考官方的文档。

Contains Join Index Repeat Replace Split Trim Fields

package main

import "fmt"
import "strings"

func main() {

    fmt.Println("字符串处理演示案例")
    // Contains Join Index Repeat Replace Split Trim Fields

    //Contains
    str1 := "hellogo"
    fmt.Println("str1 contains hello ?", (strings.Contains(str1, "hello"))) //true
    fmt.Println("str1 contains abc ?", (strings.Contains(str1, "abc")))     //false

    //Join
    str2 := []string{"a", "b", "c"}
    str3 := strings.Join(str2, "####")
    fmt.Println("str3:", str3) // a####b####c

    //Index
    fmt.Println("index:", strings.Index("abchello", "hello")) //3
    fmt.Println("index:", strings.Index("abchello", "xx"))    //-1

    //Repeat
    str4 := strings.Repeat("go", 3)
    fmt.Println("str4:", str4) //gogogo

    //Split
    str5 := "abc#123#hello"
    str6 := strings.Split(str5, "#")
    fmt.Println("str6:", str6) // [abc 123 hello]
    //Trim

    str7 := "     abc  123   hello     "
    str7 = strings.Trim(str7, " ")
    fmt.Println("str7:", str7) //abc  123   hello

    str7 = "----abc--123--hello----     "
    str7 = strings.Trim(str7, "-")
    fmt.Printf("str7:*%s*\n", str7) //*abc--123--hello----     *
    //Fields
    str8 := "     abc  123   hello     "
    str9 := strings.Fields(str8)
    fmt.Println("str9:", str9) // [abc 123 hello]

}

字符串转换

package main

import "fmt"

import "strconv"

func main() {

    fmt.Println("字符串转换演示案例")
    // Append Format Parse

    // Append:系列函数将整数等转换为字符串后,添加到现有的字节数组中
    b := make([]byte, 0, 10)
    b = strconv.AppendBool(b, false)
    b = strconv.AppendInt(b, 123, 10) //以十进制追加
    b = strconv.AppendQuote(b, "abc")
    b = strconv.AppendQuoteRune(b, '中')
    fmt.Println("b = ", b)         //[102 97 108 115 101 49 50 51 34 97 98 99 34 39 228 184 173 39]
    fmt.Println("b = ", string(b)) // false123"abc"'中'

    //Format:系列函数把其他类型的转换为字符串
    a := strconv.FormatBool(false)
    b1 := strconv.FormatInt(123, 10)
    c := strconv.FormatUint(12345, 10)
    d := strconv.Itoa(666)
    fmt.Println(a, b1, c, d) //false 123 12345 666

    fmt.Printf("%T,%T,%T,%T\n", a, b1, c, d) //string,string,string,string

    //Parse:系列函数把字符串转换为其他类型

    r1, err := strconv.ParseBool("false")
    check(err)
    r2, err := strconv.ParseInt("123", 10, 64)
    check(err)
    r3, err := strconv.ParseUint("12345", 10, 64)
    check(err)
    r4, err := strconv.Atoi("666")
    check(err)

    fmt.Println(r1, r2, r3, r4)                 //false 123 12345 666
    fmt.Printf("%T,%T,%T,%T\n", r1, r2, r3, r4) //bool,int64,uint64,int

    r5, err := strconv.Atoi("66x6")
    check(err)      //err: strconv.Atoi: parsing "66x6": invalid syntax
    fmt.Println(r5) //0
}

func check(err error) {
    if err != nil {
        fmt.Println("err:", err)

    }
}

正则表达式

正则表达式是一种进行模式匹配和文本操纵的复杂而又强大的工具。虽然正则表达式比纯粹的文本匹配效率低,但是它却更灵活。按照它的语法规则,随需构造出的匹配模式就能够从原始文本中筛选出几乎任何你想要得到的字符组合。

Go语言通过regexp标准包为正则表达式提供了官方支持,如果你已经使用过其他编程语言提供的正则相关功能,那么你应该对Go语言版本的不会太陌生,但是它们之间也有一些小的差异,因为Go实现的是RE2标准,除了\C,详细的语法描述参考:http://code.google.com/p/re2/wiki/Syntax

其实字符串处理我们可以使用strings包来进行搜索(Contains、Index)、替换(Replace)和解析(Split、Join)等操作,但是这些都是简单的字符串操作,他们的搜索都是大小写敏感,而且固定的字符串,如果我们需要匹配可变的那种就没办法实现了,当然如果strings包能解决你的问题,那么就尽量使用它来解决。因为他们足够简单、而且性能和可读性都会比正则好。

package main

import (
    "fmt"
    "regexp"
)

func main() {

    fmt.Println("正则表达式演示案例")
    buf := "abc azc a7c aac 888 a9c tac"
    //1、 提取 a.c 这样的内容
    // 1)定义规则
    reg1 := regexp.MustCompile(`a.c`)
    if reg1 == nil { //解析失败返回nil
        fmt.Println("regex err")
        return
    }
    //2)根据规则提取信息
    res := reg1.FindAllStringSubmatch(buf, -1) // 返回类型为 [][]string
    fmt.Println("res:", res)                   //[[abc] [azc] [a7c] [aac] [a9c]]
    res1 := reg1.FindAllStringSubmatch(buf, 1) // 返回类型为 [][]string
    fmt.Println("res1:", res1)                 //[[abc]]
    res2 := reg1.FindAllStringSubmatch(buf, 2) // 返回类型为 [][]string
    fmt.Println("res2:", res2)                 // [[abc] [azc]]

    //2、 提取有效小数:
    buf2 := "2.1 4.x 3.14 aac 7. .9 tac xx7.8p"
    reg2 := regexp.MustCompile(`\d+\.\d+`)
    if reg2 == nil {
        fmt.Println("regex err")
        return
    }
    res3 := reg2.FindAllStringSubmatch(buf2, -1)
    fmt.Println("res3:", res3) //[[2.1] [3.14] [7.8]]

    //2、获取html中的div标签内容
    //``   原生字符串
    buf3 := `
    
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <title>Go语言标准库文档中文版 | Go语言中文网 | Golang中文社区 | Golang中国</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
    <meta charset="utf-8">
    <link rel="shortcut icon" href="/static/img/go.ico">
    <link rel="apple-touch-icon" type="image/png" href="/static/img/logo2.png">
    <meta name="author" content="polaris <polaris@studygolang.com>">
    <meta name="keywords" content="中文, 文档, 标准库, Go语言,Golang,Go社区,Go中文社区,Golang中文社区,Go语言社区,Go语言学习,学习Go语言,Go语言学习园地,Golang 中国,Golang中国,Golang China, Go语言论坛, Go语言中文网">
    <meta name="description" content="Go语言文档中文版,Go语言中文网,中国 Golang 社区,Go语言学习园地,致力于构建完善的 Golang 中文社区,Go语言爱好者的学习家园。分享 Go 语言知识,交流使用经验">
</head>
    <div>和爱好</div>
    <div>哈哈
    你在吗
    不在
    </div>
    <div>测试</div>
    <div>你过来啊</div>

<frameset cols="15,85">
    <frame src="/static/pkgdoc/i.html">
    <frame name="main" src="/static/pkgdoc/main.html" tppabs="main.html" >
    <noframes>
    </noframes>
</frameset>
</html>
    `

    reg3 := regexp.MustCompile(`<div>(.*)</div>`)
    if reg3 == nil {
        fmt.Println("regex err")
        return
    }
    res4 := reg3.FindAllStringSubmatch(buf3, -1)
    fmt.Println("res4:", res4) //[[<div>和爱好</div> 和爱好] [<div>测试</div> 测试] [<div>你过来啊</div> 你过来啊]]

    for k, v := range res4 {
        fmt.Println(k, v)
        // 0 [<div>和爱好</div> 和爱好]
        // 1 [<div>测试</div> 测试]
        // 2 [<div>你过来啊</div> 你过来啊]
    }

    for k, v := range res4 {
        fmt.Println(k, v[1])
        // 0 和爱好
        // 1 测试
        // 2 你过来啊

    }

    fmt.Println("-----------------")
    //优化

    reg4 := regexp.MustCompile(`<div>(?s:(.*?))</div>`)
    if reg4 == nil {
        fmt.Println("regex err")
        return
    }
    res5 := reg4.FindAllStringSubmatch(buf3, -1)
    fmt.Println("res5:", res5)
    /*
            res5: [[<div>和爱好</div> 和爱好] [<div>哈哈
                你在吗
                不在
                </div> 哈哈
                你在吗
                不在
                ] [<div>测试</div> 测试] [<div>你过来啊</div> 你过来啊]]

    */

    for k, v := range res5 {
        fmt.Println(k, v[1])
        // 0 和爱好
        // 1 哈哈
        //       你在吗
        //       不在

        // 2 测试
        // 3 你过来啊

    }
}

json

JSON (JavaScript Object Notation)是一种比XML更轻量级的数据交换格式,在易于人们阅读和编写的同时,也易于程序解析和生成。尽管JSON是JavaScript的一个子集,但JSON采用完全独立于编程语言的文本格式,且表现为键/值对集合的文本描述形式(类似一些编程语言中的字典结构),这使它成为较为理想的、跨平台、跨语言的数据交换语言。

开发者可以用 JSON 传输简单的字符串、数字、布尔值,也可以传输一个数组,或者一个更复杂的复合结构。在 Web 开发领域中, JSON被广泛应用于 Web 服务端程序和客户端之间的数据通信。

Go语言内建对JSON的支持。使用Go语言内置的encoding/json 标准库,开发者可以轻松使用Go程序生成和解析JSON格式的数据。

JSON官方网站:http://www.json.org/

在线格式化:http://www.json.cn/

  1. 通过结构体生成json
    1.1 struct_tag的使用
  2. 通过map生成json
  3. json解析到结构体
  4. json解析到map
package main

import (
    "encoding/json"
    "fmt"
)

// 1. 通过结构体生成json
// 1.1 struct_tag的使用
// 2. 通过map生成json
// 3. json解析到结构体
// 4. json解析到map

//定义一个结构体类型,注意必须都要大写
type Student struct {
    Id       int
    Name     string
    Age      int
    Sex      byte
    Addr     string
    Subjects []string
}

type IT struct {
    Company string   `json:"-"`               // 不会导出到json中
    Subject []string `json:"subject"`         // 二次编码,key会变成小写
    IsOk    bool     `json:",string"`         //转换成字符串然后再输出
    Price   float64  `json:"price,omitempty"` //如果Pricer为空,则不会输出
}

type Book struct {
    Company string   `json:"company"`
    Subject []string `json:"subject"`
    IsOk    bool     `json:"isok"`
    Price   float64  `json:"price"`
}

type Book2 struct {
    Subject []string `json:"subject"`
}

func main() {

    fmt.Println("json演示案例")
    // 1. 通过结构体生成json
    s1 := Student{1, "zz", 18, 'm', "bj", []string{"c++", "java", "go"}}
    fmt.Println("s1:", s1) //{1 zz 18 109 bj}
    //func Marshal(v interface{}) ([]byte, error)
    //func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
    b1, err1 := json.Marshal(s1)
    if err1 != nil {
        fmt.Println("err1:", err1)
        return
    }
    fmt.Println("b1:", string(b1)) //{"Id":1,"Name":"zz","Age":18,"Sex":109,"Addr":"bj","Subjects":["c++","java","go"]}
    b2, err2 := json.MarshalIndent(s1, "", "    ")
    if err2 != nil {
        fmt.Println("err2:", err2)
        return
    }
    fmt.Println("b2:", string(b2))

    // {
    //       "Id": 1,
    //       "Name": "zz",
    //       "Age": 18,
    //       "Sex": 109,
    //       "Addr": "bj",
    //       "Subjects": [
    //               "c++",
    //               "java",
    //               "go"
    //       ]
    // }

    // 1.1 struct_tag的使用

    // 我们看到上面的输出字段名的首字母都是大写的,如果你想用小写的首字母怎么办呢?把结构体的字段名改成首字母小写的?
    //JSON输出的时候必须注意,只有导出的字段(首字母是大写)才会被输出,如果修改字段名,那么就会发现什么都不会输出,所以必须通过struct tag定义来实现。

    // 针对JSON的输出,我们在定义struct tag的时候需要注意的几点是:
    // l  字段的tag是"-",那么这个字段不会输出到JSON
    // l  tag中带有自定义名称,那么这个自定义名称会出现在JSON的字段名中
    // l  tag中如果带有"omitempty"选项,那么如果该字段值为空,就不会输出到JSON串中
    // l  如果字段类型是bool, string, int, int64等,而tag中带有",string"选项,那么这个字段在输出到JSON的时候会把该字段对应的值转换成JSON字符串

    it := IT{"google", []string{"c++", "java", "go"}, false, 88.88}
    fmt.Println("it:", it) //{google [c++ java go] false 88.88}
    b3, _ := json.Marshal(it)
    fmt.Println("b3:", string(b3)) //{"subject":["c++","java","go"],"IsOk":"false","price":88.88}
    b4, _ := json.MarshalIndent(it, "", "   ")
    fmt.Println("b4:", string(b4))

    // {
    //       "subject": [
    //               "c++",
    //               "java",
    //               "go"
    //       ],
    //       "IsOk": "false",
    //       "price": 88.88
    // }
    it2 := IT{"google", []string{"c++", "java", "go"}, false, 0}
    b5, _ := json.Marshal(it2)
    fmt.Println("b5:", string(b5)) //{"subject":["c++","java","go"],"IsOk":"false"} price=0的时候也不输出

    // 2. 通过map生成json

    m1 := make(map[string]interface{}, 3)
    m1["company"] = "Google"
    m1["Subject"] = []string{"c++", "java", "go"}
    m1["isOk"] = false
    m1["price"] = 3.14

    b6, _ := json.Marshal(m1)
    fmt.Println("b6:", string(b6)) //{"Subject":["c++","java","go"],"company":"Google","isOk":false,"price":3.14}
    b7, _ := json.MarshalIndent(m1, "", "   ")
    fmt.Println("b7:", string(b7))

    // {
    //        "Subject": [
    //                "c++",
    //                "java",
    //                "go"
    //        ],
    //        "company": "Google",
    //        "isOk": false,
    //        "price": 3.14
    // }

    // 3. json解析到结构体

    //可以使用json.Unmarshal()函数将JSON格式的文本解码为Go里面预期的数据结构。
    // func Unmarshal(data []byte, v interface{}) error
    //该函数的第一个参数是输入,即JSON格式的文本(比特序列),第二个参数表示目标输出容器,用于存放解码后的值。

    jsondata := []byte(`{
          "company": "Google",
          "subject": [
                  "c++",
                  "java",
                  "go"
          ],
          "isOk": "false",
          "price": 88.88
    }`)
    fmt.Println("jsondata:", string(jsondata))
    var book1 Book
    json.Unmarshal(jsondata, &book1)
    fmt.Println("book1:", book1) // {Google [c++ java go] false 88.88}

    // 只想要subjec字段
    var book2 Book2
    json.Unmarshal(jsondata, &book2)
    fmt.Println("book2:", book2) // {[c++ java go]}

    // 4. json解析到map
    fmt.Println("------------")

    m2 := make(map[string]interface{}, 4)
    json.Unmarshal(jsondata, &m2)
    fmt.Println("m2:", m2) // map[company:Google isOk:false price:88.88 subject:[c++ java go]]
    // 使用断言判m2的类型
    for k, v := range m2 {
        switch k1 := v.(type) {
        case int:
            fmt.Println(k, "is int", k1)
        case string:
            fmt.Println(k, "is string", k1)
        case bool:
            fmt.Println(k, "is bool", k1)
        case float64:
            fmt.Println(k, "is float64", k1)
        case []interface{}:
            fmt.Println(k, "is array", k1)
            for i, j := range k1 {
                fmt.Println(i, "--->", j)
            }
        }

    }

    // subject is array [c++ java go]
    // 0 ---> c++
    // 1 ---> java
    // 2 ---> go
    // isOk is string false
    // price is float64 88.88
    // company is string Google

}

文本处理

  1. WriteString的使用
  2. Read的使用
  3. 借助bufio实现按行读取内容
  4. 文件案例:拷贝文件
  1. WriteString的使用
package main

import (
    "fmt"
    "os"
    "strconv"
)

// 1. WriteString的使用
// 2. Read的使用
// 3. 借助bufio实现按行读取内容
// 4. 文件案例:拷贝文件

func main() {

    fmt.Println("文本处理演示案例")

    // 1. WriteString的使用

    f1, err := os.Create("writeString.txt")
    if err != nil {
        fmt.Println("err:", err)
        return
    }

    defer f1.Close() //main函数结束前,关闭文件

    for i := 0; i < 10; i++ {
        f1.WriteString("hello go! " + strconv.Itoa(i) + "\n")
        f1.Write([]byte("ABC\n"))
    }

    // 2. Read的使用
    // 3. 借助bufio实现按行读取内容
    // 4. 文件案例:拷贝文件
}

写入的文件内容为:

hello go! 0
ABC
hello go! 1
ABC
hello go! 2
ABC
hello go! 3
ABC
hello go! 4
ABC
hello go! 5
ABC
hello go! 6
ABC
hello go! 7
ABC
hello go! 8
ABC
hello go! 9
ABC

  1. Read的使用
package main

import (
    "fmt"
    "os"
)

// 1. WriteString的使用
// 2. Read的使用
// 3. 借助bufio实现按行读取内容
// 4. 文件案例:拷贝文件

func main() {

    fmt.Println("文本处理演示案例")

    // 2. Read的使用

    f1, err := os.Open("writeString.txt")
    if err != nil {
        fmt.Println("err:", err)
        return
    }

    defer f1.Close() //main函数结束前,关闭文件

    bytes := make([]byte, 1024) //开辟1024字节的slice作为缓存
    for {
        n, _ := f1.Read(bytes)
        if n != 0 {
            fmt.Println(string(bytes))
        } else {
            break
        }

    }
    fmt.Println("程序结束")

}

  1. 借助bufio实现按行读取内容
package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

// 1. WriteString的使用
// 2. Read的使用
// 3. 借助bufio实现按行读取内容
// 4. 文件案例:拷贝文件

func main() {

    fmt.Println("文本处理演示案例")

    // 3. 借助bufio实现按行读取内容

    f1, err := os.Open("writeString.txt")
    if err != nil {
        fmt.Println("err:", err)
        return
    }

    r := bufio.NewReader(f1)
    for {
        buffer, err := r.ReadBytes('\n')
        if err != nil {
            if err == io.EOF {
                break
            }
            fmt.Println("err = ", err)
        }
        fmt.Println("内容为:", string(buffer))
    }

    fmt.Println("程序结束")

}

  1. 文件案例:拷贝文件
package main

import (
    // "bufio"
    "fmt"
    "io"
    "os"
)

// 1. WriteString的使用
// 2. Read的使用
// 3. 借助bufio实现按行读取内容
// 4. 文件案例:拷贝文件

func main() {

    fmt.Println("拷贝文件演示案例")

    // 4. 文件案例:拷贝文件 src xxx.mp4 yyy.mp4

    list := os.Args
    fmt.Println("args:", list)
    if len(list) != 3 {
        fmt.Println("参数错误,案例:src xxx.mp4 yyy.mp4")
        return
    }
    srcFileName := list[1]
    destFileName := list[2]
    if srcFileName == destFileName {
        fmt.Println("源文件和目标文件名称不能相等")
        return
    }

    sf, err1 := os.Open(srcFileName)
    if err1 != nil {
        fmt.Println("err1", err1)
        return
    }

    df, err2 := os.Create(destFileName)
    if err2 != nil {
        fmt.Println("err2", err2)
        return
    }

    defer sf.Close()
    defer df.Close()

    buf := make([]byte, 1024)
    for {
        n, err3 := sf.Read(buf)
        if err3 != nil {
            if err3 == io.EOF {
                break
            }
            fmt.Println("err3", err3)

        }
        if n != 0 {
            df.Write(buf[:n])
        }
    }

    fmt.Println("程序结束")

}

END.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容