乐者为王

Do one thing, and do it well.

如何使用Flexbox构建新闻站点布局

英文原文:http://webdesign.tutsplus.com/tutorials/how-to-build-a-news-website-layout-with-flexbox--cms-26611

在投入并开始之前你没有必要理解Flexbox的每个方面。在这篇教程中,我们将介绍一些Flexbox的特性,同时设计一个类似The Guardian的“新闻布局”。

我们正在使用Flexbox的原因是它提供了非常强大的特性:

  • 我们可以很容易制作响应式列
  • 我们可以使列等高
  • 我们可以把内容推到容器的底部

那么让我们开始吧!

1. 从两个列开始

在CSS中创建列一直是个挑战。长期以来,唯一的选项是使用float或者table,但它们都有它们自己的问题。

Flexbox使这个过程更简单,给予我们:

  • 更简洁的代码:我们只需要一个带有display: flex的容器
  • 不需要清除float,以防止意外的布局行为
  • 语义化的标记
  • 灵活性:我们可以用几行CSS代码来调整列的大小、拉伸或者对齐列

让我们从创建两个列开始:一个是容器宽度的2/3,一个是1/3。

1
2
3
4
5
6
7
8
<div class="columns">
  <div class="column main-column">
    2/3 column
  </div>
  <div class="column">
    1/3 column
  </div>
</div>

这里有两个元素:

  • columns容器
  • 两个column子容器,其中一个带有附加的名为main-column的class,我们将用它来让该子容器更宽
1
2
3
4
5
6
7
8
9
10
11
.columns {
  display: flex;
}

.column {
  flex: 1;
}

.main-column {
  flex: 2;
}

作为有一个flex值为2的主列,它将占用其它列的两倍空间。

通过添加一些附加的视觉样式,这里是我们得到的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
html {
  font-family: sans-serif;
}

.columns {
  display: flex;
}

.column {
  background: #eee;
  border: 5px solid #ccc;
  flex: 1;
  padding: 20px;
}

.main-column {
  flex: 2;
}

2. 让每一列都成为Flexbox容器

这两列中的每一个都将包含若干垂直堆叠的文章,因此我们打算把column元素也转变成Flexbox容器。我们想要:

  • 文章被垂直堆叠
  • 文章拉伸并填充可用空间
1
2
3
4
5
6
7
8
.column {
  display: flex;
  flex-direction: column;  /* 使文章垂直堆叠 */
}

.article {
  flex: 1;  /* 拉伸文章以填补剩余的空间 */
}

容器上的flex-direction: column规则结合在子容器上的flex: 1规则确保文章将填补整个垂直空间,保持最初两列具有相同的高度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<div class="columns">
  <div class="column main-column">
    <article class="article">
      Hello World
    </article>
    <article class="article">
      Hello World
    </article>
  </div>
  <div class="column">
    <article class="article">
      Hello World
    </article>
    <article class="article">
      Hello World<br>
      Foo Bar
    </article>
    <article class="article">
      Hello World
    </article>
  </div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
html {
  font-family: sans-serif;
}

.columns {
  display: flex;
}

.column {
  background: #eee;
  border: 5px solid #ccc;
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 10px;
}

.main-column {
  flex: 2;
}

.article {
  background: mediumseagreen;
  border: 5px solid seagreen;
  color: white;
  flex: 1;
  margin: 10px;
  padding: 20px;
}

3. 让每篇文章都成为Flexbox容器

现在,为了给我们额外的控制,让我们把每篇文章也转变成一个Flexbox容器。每篇文章将包含:

  • 一个标题
  • 一个段落
  • 一个带有作者和评论数量的信息栏
  • 一张可选的响应式图片

我们在这里使用Flexbox是为了把信息栏推到底部。我们的目标文章布局如下图所示:

这里是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<a class="article first-article">
  <figure class="article-image">
    <img src="">
  </figure>
  <div class="article-body">
    <h2 class="article-title">
      <!-- 标题 -->
    </h2>
    <p class="article-content">
      <!-- 内容 -->
    </p>
    <footer class="article-info">
      <!-- 信息 -->
    </footer>
  </div>
</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.article {
  display: flex;
  flex-direction: column;
  flex-basis: auto;  /* 基于其内容设置初始元素大小 */
}

.article-body {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.article-content {
  flex: 1;  /* 这将使内容填补剩余的空间,并因此在底部压入信息栏 */
}

文章元素被垂直放置归功于flex-direction: column规则。

我们把flex: 1应用到article-content元素以便它填补空白空间,并且把article-info推到底部,无论列的高度如何。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<main class="main columns">
  <section class="column main-column">
    <a class="article first-article" href="#">
      <figure class="article-image is-4by3">
        <img src="https://s3.amazonaws.com/cms-assets.tutsplus.com/uploads/users/1366/posts/26611/attachment/image-01.png" alt="">
      </figure>
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
          Maecenas non massa sem.
          Etiam finibus odio quis feugiat facilisis.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Proin ornare magna eros.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>

    <a class="article" href="#">
      <figure class="article-image is-16by9">
        <img src="https://s3.amazonaws.com/cms-assets.tutsplus.com/uploads/users/1366/posts/26611/attachment/image-02.png" alt="">
      </figure>
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
          Maecenas non massa sem.
          Etiam finibus odio quis feugiat facilisis.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
          Maecenas non massa sem.
          Etiam finibus odio quis feugiat facilisis.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
  </section>

  <section class="column">
    <a class="article" href="#">
      <figure class="article-image is-3by2">
        <img src="https://s3.amazonaws.com/cms-assets.tutsplus.com/uploads/users/1366/posts/26611/attachment/image-03.png" alt="">
      </figure>
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
  </section>
</main>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
html {
  background: mediumseagreen;
  font-family: sans-serif;
  font-size: 14px;
}

a {
  text-decoration: none;
}

div, h2, p, figure {
  margin: 0;
  padding: 0;
}

.main {
  margin: 0 auto;
  max-width: 1040px;
  padding: 20px;
}

.columns {
  display: flex;
}

.column {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.main-column {
  flex: 2;
}

.article {
  background: white;
  color: #666;
  display: flex;
  flex: 1;
  flex-direction: column;
  flex-basis: auto;
  margin: 10px;
}

.article-image {
  background: #eee;
  display: block;
  padding-top: 75%;
  position: relative;
  width: 100%;
}

.article-image img {
  display: block;
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}

.article-image.is-3by2 {
  padding-top: 66.6666%;
}

.article-image.is-16by9 {
  padding-top: 56.25%;
}

.article-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 20px;
}

.article-title {
  color: #333;
  flex-shrink: 0;
  font-size: 1.4em;
  font-weight: bold;
  font-weight: 700;
  line-height: 1.2;
}

.article-content {
  flex: 1;
  margin-top: 5px;
}

.article-info {
  display: flex;
  font-size: 0.85em;
  justify-content: space-between;
  margin-top: 10px;
}

4. 添加一些嵌套列

在左边的列中,我们真正想要的是另一组列。因此我们将以我们已经用过的同样的columns容器代替第二篇文章。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div class="columns">
  <div class="column nested-column">
    <a class="article">
      <!-- 文章内容 -->
    </a>
  </div>

  <div class="column">
    <a class="article">
      <!-- 文章内容 -->
    </a>
    <a class="article">
      <!-- 文章内容 -->
    </a>
    <a class="article">
      <!-- 文章内容 -->
    </a>
  </div>
</div>

因为我们想要第一个嵌套列更宽,我们添加一个带有附加样式的名为nested-column的class:

1
2
3
.nested-column {
  flex: 2;
}

这将使新列的宽度是其它列的两倍。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
<main class="main columns">
  <section class="column main-column">
    <a class="article first-article" href="#">
      <figure class="article-image is-4by3">
        <img src="https://s3.amazonaws.com/cms-assets.tutsplus.com/uploads/users/1366/posts/26611/attachment/image-01.png" alt="">
      </figure>
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
          Maecenas non massa sem.
          Etiam finibus odio quis feugiat facilisis.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Proin ornare magna eros.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>

    <div class="columns">
      <div class="column nested-column">
        <a class="article" href="#">
          <figure class="article-image is-16by9">
            <img src="https://s3.amazonaws.com/cms-assets.tutsplus.com/uploads/users/1366/posts/26611/attachment/image-02.png" alt="">
          </figure>
          <div class="article-body">
            <h2 class="article-title">
              Hello World
            </h2>
            <p class="article-content">
              Lorem ipsum dolor sit amet, consectetur adipiscing elit.
              Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
              Maecenas non massa sem.
              Etiam finibus odio quis feugiat facilisis.
              Lorem ipsum dolor sit amet, consectetur adipiscing elit.
              Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
              Maecenas non massa sem.
              Etiam finibus odio quis feugiat facilisis.
            </p>
            <footer class="article-info">
              <span>By Joe Smith</span>
              <span>42 comments</span>
            </footer>
          </div>
        </a>
      </div>

      <div class="column">
        <a class="article" href="#">
          <figure class="article-image is-16by9">
            <img src="https://s3.amazonaws.com/cms-assets.tutsplus.com/uploads/users/1366/posts/26611/attachment/image-03.png" alt="">
          </figure>
          <div class="article-body">
            <h2 class="article-title">
              Hello World
            </h2>
            <p class="article-content">
              Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            </p>
            <footer class="article-info">
              <span>By Joe Smith</span>
              <span>42 comments</span>
            </footer>
          </div>
        </a>
        <a class="article" href="#">
          <div class="article-body">
            <h2 class="article-title">
              Hello World
            </h2>
            <p class="article-content">
              Lorem ipsum dolor sit amet.
            </p>
            <footer class="article-info">
              <span>By Joe Smith</span>
              <span>42 comments</span>
            </footer>
          </div>
        </a>
        <a class="article" href="#">
          <div class="article-body">
            <h2 class="article-title">
              Hello World
            </h2>
            <p class="article-content">
              Lorem ipsum dolor sit amet feugiat facilisis.
            </p>
            <footer class="article-info">
              <span>By Joe Smith</span>
              <span>42 comments</span>
            </footer>
          </div>
        </a>
      </div>
    </div>
  </section>

  <section class="column">
    <a class="article" href="#">
      <figure class="article-image is-3by2">
        <img src="https://s3.amazonaws.com/cms-assets.tutsplus.com/uploads/users/1366/posts/26611/attachment/image-04.png" alt="">
      </figure>
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
  </section>
</main>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
html {
  background: mediumseagreen;
  font-family: sans-serif;
  font-size: 14px;
}

a {
  text-decoration: none;
}

div, h2, p, figure {
  margin: 0;
  padding: 0;
}

.main {
  margin: 0 auto;
  max-width: 1040px;
  padding: 20px;
}

.columns {
  display: flex;
}

.column {
  display: flex;
  flex: 1;
  flex-direction: column;
}

.main-column {
  flex: 3;
}

.nested-column {
  flex: 2;
}

.article {
  background: white;
  color: #666;
  display: flex;
  flex: 1;
  flex-direction: column;
  flex-basis: auto;
  margin: 10px;
}

.article-image {
  background: #eee;
  display: block;
  padding-top: 75%;
  position: relative;
  width: 100%;
}

.article-image img {
  display: block;
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}

.article-image.is-3by2 {
  padding-top: 66.6666%;
}

.article-image.is-16by9 {
  padding-top: 56.25%;
}

.article-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 20px;
}

.article-title {
  color: #333;
  flex-shrink: 0;
  font-size: 1.4em;
  font-weight: bold;
  font-weight: 700;
  line-height: 1.2;
}

.article-content {
  flex: 1;
  margin-top: 5px;
}

.article-info {
  display: flex;
  font-size: 0.85em;
  justify-content: space-between;
  margin-top: 10px;
}

5. 给第一篇文章一个水平布局

第一篇文章真的很大。为了优化空间的使用,让我们把它的布局切换成水平的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.first-article {
  flex-direction: row;
}

.first-article .article-body {
  flex: 1;
}

.first-article .article-image {
  height: 300px;
  order: 2;
  padding-top: 0;
  width: 400px;
}

这里的order属性是非常有用的,因为它允许我们改变HTML元素的顺序而不影响HTML标记。在标记中article-image实际上出现在article-body的前面,但它表现的好像出现在后面

6. 使布局可响应

这些就是我们想看到的,虽然它有点儿扁平。让我们通过响应式来修复它。

Flexbox一个极好的特性是你只需要移除容器上的display: flex规则就可以完全禁用Flexbox,同时保持所有其它的Flexbox属性(例如align-items或者flex)有效。

结果是,你可以通过仅在某个断点上启用Flexbox来触发一个响应式布局。

我们将从.columns和.column选择器中移除display: flex,而不是用一个Media Query包装它们:

1
2
3
4
5
6
@media screen and (min-width: 800px) {
  .columns,
  .column {
    display: flex;
  }
}

就是这样!在更小的屏幕上,所有的文章都在彼此的上面。超过800px时,它们将会被放置在两列中。

7. 添加最后的润色

为使布局在大屏幕上更具吸引力,让我们添加一些CSS微调:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@media screen and (min-width: 1000px) {
  .first-article {
    flex-direction: row;
  }

  .first-article .article-body {
    flex: 1;
  }

  .first-article .article-image {
    height: 300px;
    order: 2;
    padding-top: 0;
    width: 400px;
  }

  .main-column {
    flex: 3;
  }

  .nested-column {
    flex: 2;
  }
}

第一篇文章的内容是水平放置的,文本在左边,图片在右边。而且,主列现在更宽(75%),嵌套列也是(66%)。这里是最终结果!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<header class="header">
  <h1>The Envato Tuts+ Report</h1>
  <h2><a href="http://webdesign.tutsplus.com/tutorials/how-to-build-a-news-website-layout-with-flexbox--cms-26611">Read tutorial</a></h2>
</header>

<main class="main columns">
  <section class="column main-column">
    <a class="article first-article" href="#">
      <figure class="article-image is-4by3">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/210284/image-01-lo.jpg" alt="">
      </figure>
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
          Maecenas non massa sem.
          Etiam finibus odio quis feugiat facilisis.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Proin ornare magna eros.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>

    <div class="columns">
      <div class="column nested-column">
        <a class="article" href="#">
          <figure class="article-image is-16by9">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/210284/image-02-lo.jpg" alt="">
          </figure>
          <div class="article-body">
            <h2 class="article-title">
              Hello World
            </h2>
            <p class="article-content">
              Lorem ipsum dolor sit amet, consectetur adipiscing elit.
              Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
              Maecenas non massa sem.
              Etiam finibus odio quis feugiat facilisis.
              Lorem ipsum dolor sit amet, consectetur adipiscing elit.
              Proin ornare magna eros, eu pellentesque tortor vestibulum ut.
              Maecenas non massa sem.
              Etiam finibus odio quis feugiat facilisis.
            </p>
            <footer class="article-info">
              <span>By Joe Smith</span>
              <span>42 comments</span>
            </footer>
          </div>
        </a>
      </div>

      <div class="column">
        <a class="article" href="#">
          <figure class="article-image is-16by9">
            <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/210284/image-03-lo.jpg" alt="">
          </figure>
          <div class="article-body">
            <h2 class="article-title">
              Hello World
            </h2>
            <p class="article-content">
              Lorem ipsum dolor sit amet, consectetur adipiscing elit.
            </p>
            <footer class="article-info">
              <span>By Joe Smith</span>
              <span>42 comments</span>
            </footer>
          </div>
        </a>
        <a class="article" href="#">
          <div class="article-body">
            <h2 class="article-title">
              Hello World
            </h2>
            <p class="article-content">
              Lorem ipsum dolor sit amet.
            </p>
            <footer class="article-info">
              <span>By Joe Smith</span>
              <span>42 comments</span>
            </footer>
          </div>
        </a>
        <a class="article" href="#">
          <div class="article-body">
            <h2 class="article-title">
              Hello World
            </h2>
            <p class="article-content">
              Lorem ipsum dolor sit amet feugiat facilisis.
            </p>
            <footer class="article-info">
              <span>By Joe Smith</span>
              <span>42 comments</span>
            </footer>
          </div>
        </a>
      </div>
    </div>
  </section>

  <section class="column">
    <a class="article" href="#">
      <figure class="article-image is-3by2">
        <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/210284/image-04-lo.jpg" alt="">
      </figure>
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
    <a class="article" href="#">
      <div class="article-body">
        <h2 class="article-title">
          Hello World
        </h2>
        <p class="article-content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
        <footer class="article-info">
          <span>By Joe Smith</span>
          <span>42 comments</span>
        </footer>
      </div>
    </a>
  </section>
</main>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700);
@import url(https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css);

html {
  background: mediumseagreen;
  font-size: 14px;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  min-width: 300px;
  overflow-x: hidden;
  overflow-y: scroll;
  text-rendering: optimizeLegibility;
}

body {
  color: #666;
  font-family: "Source Sans Pro", "Helvetica", "Arial", sans-serif;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.4;
}

a {
  text-decoration: none;
  transition: all 0.3s cubic-bezier(.25, .8, .25, 1);
}

div, h2, p, figure {
  margin: 0;
  padding: 0;
}

.header {
  color: white;
  padding: 40px 0 20px;
  text-align: center;
}

.header h1 {
  font-size: 40px;
  font-weight: bold;
}

.header h2 a {
  border-bottom: 1px solid rgba(255, 255, 255, 0.5);
  color: white;
  font-size: 20px;
  opacity: 0.5;
}

.header h2 a:hover {
  border-bottom-color: white;
  opacity: 1;
}

.main {
  margin: 0 auto;
  max-width: 1040px;
  padding: 10px;
}

.column {
  flex: 1;
  flex-direction: column;
}

.article {
  background: white;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
  color: #666;
  display: flex;
  flex: 1;
  flex-direction: column;
  flex-basis: auto;
  margin: 10px;
}

.article:hover,
.article:focus {
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
  color: #444;
}

.article-image {
  background: #eee;
  display: block;
  padding-top: 75%;
  position: relative;
  width: 100%;
}

.article-image img {
  display: block;
  height: 100%;
  left: 0;
  position: absolute;
  top: 0;
  width: 100%;
}

.article-image.is-3by2 {
  padding-top: 66.6666%;
}

.article-image.is-16by9 {
  padding-top: 56.25%;
}

.article-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 20px;
}

.article-title {
  color: #333;
  flex-shrink: 0;
  font-size: 1.4em;
  font-weight: 700;
  line-height: 1.2;
}

.article-content {
  flex: 1;
  margin-top: 5px;
}

.article-info {
  display: flex;
  font-size: 0.85em;
  justify-content: space-between;
  margin-top: 10px;
}

@media screen and (min-width: 800px) {
  .columns,
  .column {
    display: flex;
  }
}

@media screen and (min-width: 1000px) {
  .first-article {
    flex-direction: row;
  }

  .first-article .article-body {
    flex: 1;
  }

  .first-article .article-image {
    height: 300px;
    order: 2;
    padding-top: 0;
    width: 400px;
  }

  .main-column {
    flex: 3;
  }

  .nested-column {
    flex: 2;
  }
}

总结

我希望我已经向你展示在投入和开始使用Flexbox前你不需要理解它的每个方面!响应式新闻布局是一个真正有用的模式。拆解它,把玩它,让我们知道你是如何进展的!

逻辑题-谁养鱼

  1. 在一条街上,有5座房子,喷了5种颜色。
  2. 每座房子里住着不同国籍的人。
  3. 每个人喝不同的饮料,抽不同品牌的香烟,养不同的宠物。

问题是:谁养鱼?

提示:

  1. 英国人住红色房子。
  2. 瑞典人养狗。
  3. 丹麦人喝茶。
  4. 绿色房子在白色房子左面。
  5. 绿色房子主人喝咖啡。
  6. 抽Pall Mall香烟的人养鸟。
  7. 黄色房子主人抽Dunhill香烟。
  8. 住在中间房子的人喝牛奶。
  9. 挪威人住第一间房子。
  10. 抽Blends香烟的人住在养猫的人隔壁。
  11. 养马的人住抽Dunhill香烟的人隔壁。
  12. 抽Blue Master的人喝啤酒。
  13. 德国人抽Prince香烟。
  14. 挪威人住蓝色房子隔壁。
  15. 抽Blends香烟的人有一个喝水的邻居。

在回答上述问题前先画一个6行5列的表格,从上到下的每一行分别代表房子的顺序(A表示左边第一间房子)、哪国人、房子颜色、饮料、香烟、宠物。下表是问题的初始状态:

A B C D E
? ? ? ? ?
? ? ? ? ?
? ? ? ? ?
? ? ? ? ?
? ? ? ? ?

根据提示8、9和14可以得到:

A B C D E
挪威人 ? ? ? ?
? 蓝色 ? ? ?
? ? 牛奶 ? ?
? ? ? ? ?
? ? ? ? ?

由提示4和5可以判定房子D的颜色是绿色,房子主人喝咖啡,房子E的颜色是白色。如下表所示:

A B C D E
挪威人 ? ? ? ?
? 蓝色 ? 绿色 白色
? ? 牛奶 咖啡 ?
? ? ? ? ?
? ? ? ? ?

结合提示1、7和11可以知道房子C是红色的,住的是英国人,房子A是黄色的。挪威人抽Dunhill香烟。住房子B的人养马。如下表所示:

A B C D E
挪威人 ? 英国人 ? ?
黄色 蓝色 红色 绿色 白色
? ? 牛奶 咖啡 ?
Dunhill ? ? ? ?
? ? ? ?

依据上表可知,挪威人喝的饮料是水、茶或者啤酒。结合提示3和12可以断定挪威人喝的是水。如下表所示:

A B C D E
挪威人 ? 英国人 ? ?
黄色 蓝色 红色 绿色 白色
? 牛奶 咖啡 ?
Dunhill ? ? ? ?
? ? ? ?

通过提示15可以得出住房子B的人抽Blends香烟。如下表所示:

A B C D E
挪威人 ? 英国人 ? ?
黄色 蓝色 红色 绿色 白色
? 牛奶 咖啡 ?
Dunhill Blends ? ? ?
? ? ? ?

结合提示12可以推断住房子E的人抽Blue Master香烟、喝啤酒。住房子B的人喝茶。如下表所示:

A B C D E
挪威人 ? 英国人 ? ?
黄色 蓝色 红色 绿色 白色
牛奶 咖啡 啤酒
Dunhill Blends ? ? Blue Master
? ? ? ?

由提示3、13得到房子B住的是丹麦人。房子D住的是德国人,抽Prince香烟。如下表所示:

A B C D E
挪威人 丹麦人 英国人 德国人 ?
黄色 蓝色 红色 绿色 白色
牛奶 咖啡 啤酒
Dunhill Blends ? Prince Blue Master
? ? ? ?

再由提示6和10确定住房子C的人抽Pall Mall香烟、养鸟。挪威人养猫。如下表所示:

A B C D E
挪威人 丹麦人 英国人 德国人 ?
黄色 蓝色 红色 绿色 白色
牛奶 咖啡 啤酒
Dunhill Blends Pall Mall Prince Blue Master
? ?

最后结合提示2推断得到房子E住的是瑞典人,养狗。如下表所示:

A B C D E
挪威人 丹麦人 英国人 德国人 瑞典人
黄色 蓝色 红色 绿色 白色
牛奶 咖啡 啤酒
Dunhill Blends Pall Mall Prince Blue Master
?

现在,结果已经出来了:德国人养鱼。

开发者被灯光蒙蔽了双眼

英文原文:http://programmingzen.com/2008/12/30/developers-are-blinded-by-the-light/

Blinded by the light,
revved up like a deuce,
another runner in the night
— Bruce Springsteen

人类在计算几率方面是异常地差。我们有限的经验强烈地影响着我们对事件的可能性的认知。例如,我们往往极大地高估由恐怖袭击、意外枪支走火或者飓风引起死亡的几率,并且极大地低估像坠落、溺水或者流感死亡的原因。其原因是媒体经常提醒我们恐怖主义、飓风的危险或者关于孩子们被意外射杀的瞬间故事。你很少发现关于一个人溺水、坠落或者由于流感死亡的故事在国家新闻频道上被报道。新闻报道有一种倾向是耸人听闻,为的是引起人们的注意和钩住大量的观众,因此当谈到估计什么可能/不可能发生时它们促成人们的偏见。

同样的,在电视和报纸上过度曝光心花怒放的彩票中奖者举起他们超大的支票往往歪曲人们对通过购买一注彩票胜利的可能性的认知。对这个问题持一个严谨和客观的态度将会很快揭露中奖的几率比它们表面上看起来的要差得多。[1]

我注意到这种情况也正在开发/创业的世界里发生。这是一波新的淘金热。太多的开发者正在试图建立下一个大的社交网络,成为下一个Facebook(或YouTube),聚集数以百万计的人群,希望被大公司以一笔数量荒谬的钱收购。媒体喜欢这类故事。

因此,正在试图构建下一个Facebook的开发者类似于彩票买家。他们中的一些人会成功和获胜,但大部分人会惨遭失败。我们真正需要多少社交网络?广告支撑的模式适合某些设法吸引庞大的人群同时保持其费用最低(例如PlentyOfFish)或者被收购(例如YouTube,它也在花Google的钱)的幸运的公司。在这个过程中其他人都是在烧钱以及浪费VC的钱和诚意。

我担心很多开发者被灯光蒙蔽了双眼。他们对获得成功的真实几率的认知受到了媒体连续报道的百万——如果不是10亿——美元收购和成功故事的扭曲。而且有些VC鼓励这种行为,希望能在他们的投资上看到高回报。毕竟这些都是非常富有的人,他们对小规模的成功不感兴趣。

除了明显的浪费时间和资源之外,我认为许多开发者为了追求极不可能的结果放弃了极好的机会。用一个传统商业计划挣1,000万的可能性和按YouTube的方式挣10亿的可能性的比例,与这些金额能负担得起你的不同生活质量不成正比。如果你破产了,有3万美元的信用卡债务,或者你是中产阶级,你会发现1,000万美元可以提高的生活质量总是远远超过从1,000万到10亿能提高的。而且重要的是,我们要认识到瞄准尽管更小,但更有可能的结果不会以任何方式阻止你以后的“伟大梦想”,一旦你的第一次(或者第一次成功的)创业已经取得了成功。

你愿意参加20次有1次胜利机会的100万美元抽奖,还是50,000,000次有1次机会的5亿美元抽奖?理性的人会选择第1个,然而在今天,大部分创业公司都倾向于选择第2个。他们这么做是因为他们极大地高估了他们以第2个抽奖成功的几率。

创建一个产品并让人们为它付费。不要拿VC的钱,除非你真的不考虑依靠自己的力量启动你的公司。软件世界的主要优点之一是在开始的时候极少量的资本需要。如果你想做Web应用,可以使用软件即服务(SaaS)模型,让你的用户为你提供的软件和服务付费。你将会有更加少的受众,更少的可伸缩性问题和费用,以及有更多的收入和更大的盈利机会。Joel Spolsky(和他那华丽的办公空间)挣得数百万收入是因为他的公司在出售一套Web版的bug追踪器。你知道有多少免费的bug追踪器?在这个市场上存在多少竞争对手?我确信有许多。然而,虽然Joel的人气毫无疑问地帮助到了他的公司,但此案例仍然展示了一个企业如何通过构建一个更好的产品而成功。

就像David Heinemeier Hansson提及的,有无数不受关注的公司在像那样挣钱。[2]如果你把视线从聚光灯上移开,你将看到许多公司在它们所做的事情上面非常成功,尽管它们不出名或者没有制造新闻头条。它们中的有些公司实际上努力不去吸引太多的关注到它们的成功上(经常用数百万美元来衡量),以便防止竞争对手的涌现。

不管你的名字是不是家喻户晓,你甚至不必创建Web应用才能非常成功。你可能会想到为智能手机包括iPhone开发移动应用。但是良好的老式桌面应用让各种各样的软件公司继续发展。这就是为什么“你不能再用商业桌面软件挣钱,或者桌面应用都死了”的扭曲的认知太荒谬的原因。作为开发者/微型ISV/创业公司,你用良好设计的桌面软件挣钱的机会远远高于构建任何一款YouTube、Flickr或者Facebook复制品的机会。

要了解我们的认知是怎么被扭曲的,你只需要和那些公开分享它们软件销售统计的公司交谈。你将会被用相对普通的软件挣到钱的数额震惊。Balsamiq制作了一款UI草图应用卖79美元。作者成功挣到了10万美元收入在前5个月,大部分是通过销售应用的桌面版本。在这个产业里他当然远非最大的赢家之一。我提到这个不过是因为它表明那是一个非常不错的想法,很好执行,当你让你的用户付费时能很快带来收入。如果你认为在5个月里10万美元很少,那我来问你有多少免费网站达成一个类似的每月收入净额。如果你正在寻找更大的收入,了解下Omni Graffle,它给Omni Group赚取了数百万美元,或者把你的目光放到B2B应用上(在那个市场里某些应用卖上千美元一份)。

当许多开发者被灯光蒙蔽了双眼的时候,有创业想法的智者正在建立真正的软件业务。我请你走出来做同样的事情。

脚注

[1] 我在这里总结的概念被Dan Gilbert在这个TED演讲里更详细地说明了。

[2] David Heinemeier Hansson在他的一篇帖子中持类似的观点,该帖给了本文以灵感。

哪些书不要读

为什么要列这个资源?因为某些书读完之后往往会有浪费时间的感觉。为了帮助各位读者节省时间,我决定在我看过的书中选出一份合适的书单,并给出我的观点,方便读者在购书和选书时作出取舍。本清单离详尽还很远(会不断更新的),而且难免带有本人的主观偏见,所以各位如果觉得有什么错漏的话,可以在评论区给我留言。

计算机

《像程序员一样思考》

点评:这是一本教你学会如何解决编程问题的书。但实际上只有第1、第7和第8章值得一读。

经济学

《郎咸平说:我们的日子为什么这么难》

点评:提出的观点都是当前大家关心的问题,可惜他只是财务和公司治理专家,不是经济学专家,所提的解决方案或说的话也只是让大家心中的郁闷可以有机会发泄下,所以郎咸平的其它关于经济学的书籍你就可以不要看了。如果你想学公司财务方面的东西,那么他的论文(注意不是书,是发表过的学术论文)是一定要读的。延伸阅读是东方出版社搞的,而非郎咸平,推荐的也都是该出版社的书。

《货币战争》

点评:又是一本博大众眼球的书。可是一个连美联储是私有的都要当作秘密大声来讲的作者你就知道他是什么水平了,这些可是人家美联储官方网站上都黑纸白纸写出来的。其它什么断章取义、胡乱拼凑的就不要讲了,我读了一部分就看不下去,把它扔角落里去了。以前还写过一篇博文来讲这本书是如何混淆读者视听的,只是可惜没有完成。

《魔鬼经济学》

点评:引用郭凯的话“虽然书里的每个故事都是基于作者的实证研究,可是他的那些实证研究没有一个不存在致命缺陷,他所有的结论事后都被更仔细的研究推翻了。”

《13个严重的经济学谬误》

点评:这本书有点专业,且翻译的极为糟糕,好些语句和段落不甚通顺,所以部分内容读起来有种似是而非的感觉。翻译后的书名加上“经济学的真相”,完全是想用耸人听闻的标题吸引读者的注意。该书最值得看的是《前言》和《一份经济学研究方法的备忘录》,尤其是后者,可以让你了解一些经济学观点是怎么得出的。谬误1整篇文章几乎看不出是在证明命题的错误;谬误3中的印度可以用中国替代。作者的观点看似有理其实偏颇,看过郭凯的《王二的经济学故事》中关于汇率的文章就可以知道,印度出口商品换成美元结余,只劳动不消费,相当于给美国白打工;印度坚持高估美元,虽然可以保持它在与美国贸易中的顺差地位,但这种强制性的高估实际上是在用贸易补贴美国。谬误5虽然讲的有道理,但实在想不明白作者是如何得到租金限制法令的几个特征的!谬误7中房屋的建筑成本是不包含土地价格的,这种违背常识的假设会增加理解的困难。而且,设定房屋价格后再去谈论削减建筑成本不会影响房价,怎么看怎么觉得奇怪,虽然我同意他关于削减建筑成本不会降低房价的观点。谬误9的第4段翻译的极其马虎,明显有两个人翻译的痕迹,错字漏字导致边际成本傻傻的说不清。

《一切皆有价》

点评:书名标题很诱人,容易引起读者进一步阅读的欲望,可惜内容只是大量数据和案例的罗列,毫无作者自己的观点。

书法

《书法有法》

点评:全书可用“转笔”二字一言蔽之。但疑惑的是,既然她这么推崇转笔,并且通过私相授受的方式从长辈手中得以传承这个笼罩着神秘、高深莫测、技巧高难、妙不可言的笔法的不传之秘,为什么她在书写时却几乎不用呢?而且文中对古人论述书法的言论的解释多有牵强附会之处。

贫富差距精简版

英文原文:http://paulgraham.com/sim.html

2016年1月

正如经常发生的那样——当说一些有争议的话题时,已经有我刚写的一篇贫富差距的文章的一些非常新奇的解释。我想这可能有助于澄清问题,如果我试着写一个简简单单、没有误解的版本。

很多人谈论贫富差距。几乎所有人都说贫富差距增大是坏的,贫富差距缩小是好的。

但是贫富差距本身并非坏事。它有多方面的原因。很多是坏的,但有些是好的。

例如,高入狱率和税收漏洞是增大贫富差距的不良因素。

但是创业同样地增大贫富差距。创业成功的创始人最终会得到值很多钱的股票。

而且不像高入狱率和税收漏洞,创业整体上是好的。

既然贫富差距本身并非坏事,我们就不应该攻击它。相反,我们应该攻击那些造成贫富差距的不良因素。

例如,我们应该攻击贫穷,而不是攻击贫富差距。

攻击贫富差距是双重错误。它会损害好的和坏的原因。但更糟的是,这是一个攻击坏的原因的无效方式。

除非我们直接攻击坏的贫富差距原因,否则我们不能做好解决它们的工作。

但是,如果我们解决了所有坏的贫富差距原因,我们依然将增加贫富差距的水平,因为正在增长的技术力量。

ANTLR 4权威参考读书笔记(8)

  • syntax analyzer 语法分析器
  • syntax tree 语法树

一门语言由有效的句子组成,一个句子由短语组成,一个短语由子短语和词汇符号组成。要实现一门语言,我们必须构建一个能读取句子以及对发现的短语和输入符号作出适当反应的应用。

这样的应用必须能识别特定语言的所有有效的句子、短语和子短语。识别一个短语意味着我们能确定短语的各种组件并能指出它与其它短语的区别。例如,我们把输入a=5识别为赋值语句,这就意味着我们知道a是赋值目标以及5是要存储的值。识别赋值语句a=5也意味着应用认为它是明显不同于,比如说,a+b语句的。在识别后,应用将执行适当的操作,例如performAssignment("a", 5)或者translateAssignment("a", 5)。

识别语言的程序被称为语法分析器。语法指代控制语言成员的规则,每条规则都表示一个短语的结构。为了更容易地实现识别语言的程序,通常我们会把识别语言的语法分析拆解成两个相似但不同的任务或阶段。

把字符组成单词或符号(记号)的过程被称为词法分析或简单标记化。我们把标记输入的程序称为词法分析器。词法分析器能把相关的记号组成记号类型,例如INT(整数)、ID(标志符)、FLOAT(浮点数)等。当语法分析器只关心类型的时候,词法分析器会把词汇符号组成类型,而不是单独的符号。记号至少包含两块信息:记号类型(确定词法结构)和匹配记号的文本。

第二阶段是真正的语法分析器,它使用这些记号去识别句子结构,在本例中是赋值语句。默认情况下,ANTLR生成的语法分析器会构建一个称为语法分析树或语法树的数据结构,它记录语法分析器如何识别输入句子的结构和它的组件短语。下图阐明了语言识别器的基本数据流:

语法分析树的内部节点是分组和确认它们子节点的短语名字。根节点是最抽象的短语名字,在本例中是prog(“program”的缩写)。语法分析树的叶子节点永远是输入记号。

通过生成语法分析树,语法分析器给应用的其余部分提供了方便的数据结构,它们含有关于语法分析器如何把符号组成短语的完整信息。树是非常容易处理的,并且也能被程序员很好的理解。更好的是,语法分析器能自动地生成语法分析树。

通过操作语法分析树,需要识别相同语言的多个应用能重用同一个语法分析器。当然,你也可以选择直接在语法中嵌入特定应用的代码片段,这是语法分析器生成器传统的做法。ANTLR v4仍然允许这样做,但是语法分析树有助于更简洁更解耦的设计。

语法分析树对于需要多次树遍历的转换也是非常有用的,因为在计算依赖关系的阶段通常会需要前一个阶段的信息。相比于在每个阶段都要准备输入字符,我们只需要遍历语法分析树多次,更具有效率。

因为我们用一套规则指定短语,语法分析树子树根节点对应于语法规则名。这里的语法规则对应于上图中assign子树的第一层:

1
assign : ID '=' expr ;    // 匹配赋值语句像"a=5"

明白ANTLR如何把这些规则转换为人类可读的语法分析代码是使用和调试语法的基础,因此让我们深入地挖掘语法分析是如何工作的。

ANTLR 4权威参考读书笔记(7)

  • sequence 序列

ANTLR 4权威参考读书笔记(6)中的这些操作仅仅是提取和打印被语法分析器匹配的值,它们并没有改变语法分析器本身。

实际上,操作还可以影响语法分析器如何识别输入短语。这类特殊的操作被称为语义谓词。下面我们会用一个简单的例子来展示语义谓词的强大能力:动态地打开和关闭语法的某个部分。

使用语义谓词改变语法分析

有一个读入整数序列的语法,它的玄机是由输入的部分指定有多少个整数组合在一起,所以我们必须等到运行时才能知道有多少整数被匹配。这里是示例输入文件idata.txt的内容:

1
2 9 10 3 1 2 3

第1个数字表示匹配后续两个数字9和10;紧跟10的数字3表示匹配接下来的三个数字。我们的目的是设计一个语法IData.g,把9和10组合在一起,把1、2和3组合在一起。在语法上执行以下命令后显示的语法分析树能够清楚地标识出整数的分组,就像下图显示的那样:

1
2
3
antlr -no-listener IData.g
compile *.java
grun IData file -gui idata.txt

要达成这个目标,以下语法中的关键是一个被称为语义谓词的布尔值操作:{$i < $n}?。当谓词计算结果为true时,语法分析器匹配整数直到超过序列规则参数n要求的数量;当计算结果为false时,谓词让相关的选项从生成的语法分析器中“消失”。 在这个案例中,值为false的谓词让(...)*循环从规则序列里终止并返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
grammar IData;

file : group+ ;

group: INT sequence[$INT.int] ;

sequence[int n]
locals [int i = 1;]
     : ( {$i<=$n}? INT {$i++;} )*  // match n integers
     ;

INT  : [0-9]+ ;  // match integers
WS   : [ \t\n\r]+ -> skip ;  // toss out all whitespace

被语法分析器使用的规则序列的内部语法表示看起来就像下图这样:

虚线表明谓词可以剪断那条路径,只给语法分析器留下一个选择:退出的路径。

虽然大部分时间我们不需要这样的微管理,但它至少让我们知道我们有这样的武器可以处理病理分析问题。