{ }codelper
步长循环三元运算符补齐对齐P0126

多月日历

编写一个程序,连续输出几个月的日历。
第一行给出月数 k 和第一个月 1 日的星期 w。
星期用 0 表示星期日,1 星期一,2 星期二,3 星期三,4 星期四,5 星期五,6 星期六。
第二行依次给出每个月的天数,共 k 个。
下个月的 1 日是上个月最后一天的下一个星期。
每个月一周输出一行,一行是从星期日到星期六的七格。
第一行是包含 1 日的那一周,最后一行是包含最后一天的那一周。
每格宽两个字符,日期右对齐(一位数日期前面加一个空格)。
1 日之前的格子用两个空格填充。
格子之间放一个空格。
行末空格不评判,所以最后一天之后的格子可以输出也可以不输出。
月与月之间输出一个空行。

输入
1 ≤ k ≤ 12,0 ≤ w ≤ 6,每月天数在 28 到 31 之间
输出
每月 4~6 行,月与月之间一个空行
样例 1 · stdin
2 3
30 31
stdout
          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

                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
main.py
输入(stdin)

运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

把每周星期日的日期从 1 - w 开始每次加 7(0 及以下表示上个月的格子),就不必另外计算行数。
每次加 7 的循环:Python range(1 - w, n + 1, 7)(终点 n + 1 不包含),C 系、JS、TS for (s = 1 - w; s <= n; s += 7),Craykon 循环 (s = 1 - w; s <= n; s += 7)。
常见陷阱有三个。
Python 中把终点写成 n,当 n 日是星期日时会漏掉最后一周。
用 (w + n) / 7 + 1 计算行数,恰好在星期六结束的月份会多出一个空行。
下个月的星期是 (w + n) % 7(w + n - 1 是最后一天的星期)。
填格子只需一个三元运算:Python f"{d:2d}" if 1 <= d <= n else " "(条件在中间),其他语言 条件 ? 值 : 值。
右对齐:Python f"{d:2d}",JS/TS String(d).padStart(2)(padEnd 是左对齐,会错),Java String.format("%2d", d),C# d.ToString().PadLeft(2),C printf("%2d"),C++ std::setw(2),Craykon ("" + d).左填充(2)。

Pythonmain.py · 12 行
k, w = map(int, input().split())lengths = list(map(int, input().split()))months = []for n in lengths:    lines = []    # 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)    for start in range(1 - w, n + 1, 7):        cells = [f"{d:2d}" if 1 <= d <= n else "  " for d in range(start, start + 7)]        lines.append(" ".join(cells).rstrip())    months.append("\n".join(lines))    w = (w + n) % 7  # 다음 달 1일의 요일print("\n\n".join(months))
JavaScriptmain.js · 15 行
const [, first, ...lengths] = require("fs").readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let w = first;const months = [];for (const n of lengths) {  const lines = [];  // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)  for (let start = 1 - w; start <= n; start += 7) {    const cells = [];    for (let d = start; d < start + 7; d++) cells.push(d >= 1 && d <= n ? String(d).padStart(2) : "  ");    lines.push(cells.join(" ").trimEnd());  }  months.push(lines.join("\n"));  w = (w + n) % 7; // 다음 달 1일의 요일}console.log(months.join("\n\n"));
TypeScriptmain.ts · 16 行
import { readFileSync } from "node:fs";const [, first, ...lengths]: number[] = readFileSync(0, "utf8").trim().split(/\s+/).map(Number);let w: number = first;const months: string[] = [];for (const n of lengths) {  const lines: string[] = [];  // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)  for (let start = 1 - w; start <= n; start += 7) {    const cells: string[] = [];    for (let d = start; d < start + 7; d++) cells.push(d >= 1 && d <= n ? String(d).padStart(2) : "  ");    lines.push(cells.join(" ").trimEnd());  }  months.push(lines.join("\n"));  w = (w + n) % 7; // 다음 달 1일의 요일}console.log(months.join("\n\n"));
JavaMain.java · 25 行
import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int k = sc.nextInt();        int w = sc.nextInt();        StringBuilder out = new StringBuilder();        for (int m = 0; m < k; m++) {            int n = sc.nextInt();            if (m > 0) out.append('\n');            // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)            for (int start = 1 - w; start <= n; start += 7) {                StringBuilder line = new StringBuilder();                for (int d = start; d < start + 7; d++) {                    if (d > start) line.append(' ');                    line.append(d >= 1 && d <= n ? String.format("%2d", d) : "  ");                }                out.append(line.toString().stripTrailing()).append('\n');            }            w = (w + n) % 7; // 다음 달 1일의 요일        }        System.out.print(out);    }}
C#Main.cs · 30 行
using System;using System.Collections.Generic;using System.Text; class Program{    static void Main()    {        string[] first = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int w = int.Parse(first[1]);        string[] lengths = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        var months = new List<string>();        foreach (string s in lengths)        {            int n = int.Parse(s);            var lines = new List<string>();            // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)            for (int start = 1 - w; start <= n; start += 7)            {                var cells = new List<string>();                for (int d = start; d < start + 7; d++)                    cells.Add(d >= 1 && d <= n ? d.ToString().PadLeft(2) : "  ");                lines.Add(string.Join(" ", cells).TrimEnd());            }            months.Add(string.Join("\n", lines));            w = (w + n) % 7; // 다음 달 1일의 요일        }        Console.WriteLine(string.Join("\n\n", months));    }}
C++main.cpp · 23 行
#include <iomanip>#include <iostream>#include <string> int main() {    int k, w;    std::cin >> k >> w;    for (int m = 0; m < k; m++) {        int n;        std::cin >> n;        if (m > 0) std::cout << '\n';        // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)        for (int start = 1 - w; start <= n; start += 7) {            for (int d = start; d < start + 7 && d <= n; d++) {                if (d > start) std::cout << ' ';                if (d >= 1) std::cout << std::setw(2) << d;                else std::cout << "  ";            }            std::cout << '\n';        }        w = (w + n) % 7; // 다음 달 1일의 요일    }}
Cmain.c · 23 行
#include <stdio.h> int main(void) {    int k, w;    scanf("%d %d", &k, &w);    for (int m = 0; m < k; m++) {        int n;        scanf("%d", &n);        if (m > 0) putchar('\n');        // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)        for (int start = 1 - w; start <= n; start += 7) {            // 마지막 날 뒤 칸은 줄 끝 빈칸이라 찍지 않는다            for (int d = start; d < start + 7 && d <= n; d++) {                if (d > start) putchar(' ');                if (d >= 1) printf("%2d", d);                else printf("  ");            }            putchar('\n');        }        w = (w + n) % 7; // 다음 달 1일의 요일    }    return 0;}
Craykonmain.cray · 23 行
kw = 控制台.读数字();k = kw[0];w = kw[1];lengths = 控制台.读数字();循环 (m = 0; m < k; m++){    n = lengths[m];    如果 (m > 0)    {        控制台.输出("");    }    // 한 주의 일요일 날짜: 1 - w부터 7씩 건너뛴다(0 이하면 지난달 칸)    循环 (start = 1 - w; start <= n; start += 7)    {        cells = [];        循环 (d = start; d < start + 7; d++)        {            cells.添加(d >= 1 && d <= n ? ("" + d).左填充(2) : "  ");        }        控制台.输出(cells.连接(" "));    }    w = (w + n) % 7; // 다음 달 1일의 요일}