#include<iostream>
#include<cctype>
#include<cstring>
using namespace std;
const int MAX_LENGTH = 1500;
//真的想不到要怎麼解只能採用暴力解了嗚嗚嗚
//基本上這個就是小孩勞作 剪剪貼貼就解完ㄌ...
int main()
{
char inputString[MAX_LENGTH] = {0};
cin.getline(inputString, MAX_LENGTH);
char outputString[MAX_LENGTH] = {0};
char *checkPointers = inputString;//用來記錄函式中處理位置的指標
for(int i = 0; i < MAX_LENGTH; i++)//do first step process so there is no situation like " ""punct"" "
{
if(isblank(inputString[i]) != 0)//第 i + 1個是空白的話
{
if(isalnum(inputString[i + 1]) != 0)//再檢查他的下一個是不是文字或數字 是的話就留空格
{
strncat(outputString, checkPointers, &inputString[i] - checkPointers);//用指標的差值來決定要貼多少字
for(int j = 0; j < MAX_LENGTH; j++)
{
if(outputString[j] == '\0')
{
outputString[j] = ' ';//因為會strncat會貼在從第一個數過來的第一個\0上面所以透過更改\0的位置來控制空格
outputString[j + 1] = '\0';
break;
}
}
//cout << outputString << endl;
checkPointers = &inputString[i+1];//更新一下位置的指標去決定下一條要切的位置
}
else if(ispunct(inputString[i + 1]) != 0)//是標點符號的話就先接在字上面
{
strncat(outputString, checkPointers, &inputString[i] - checkPointers);
checkPointers = &inputString[i+1];
}
}
else if(inputString[i+1] == '\0')//碰到\0就先跳出這個條件判斷
{
strncat(outputString, checkPointers, &inputString[i+1] - checkPointers);//記得要貼最後一個指標到\0之間的東西
break;
}
}
//cout << outputString << endl;
for(int i = 0; i < MAX_LENGTH; i++) //把修改完的都丟到input裡面 (我都從input當中索引) 這樣也不用開太多陣列 就只是有點複雜
{
inputString[i] = outputString[i];
}
checkPointers = inputString;//重置
outputString[0] = '\0';//把輸出陣列歸0
for(int i = 0; i < MAX_LENGTH; i++)
{
if(ispunct(inputString[i - 1]) != 0 && isblank(inputString[i]) != 0)//這個也是先讓所有的標點符號先黏在一起 反正就是先讓標點符號的左右邊不要有任何的空格 影響判斷
{
strncat(outputString, checkPointers, &inputString[i] - checkPointers);
checkPointers = &inputString[i+1];
}
else if(inputString[i + 1] == '\0')
{
strncat(outputString, checkPointers, &inputString[i + 1] - checkPointers);
break;
}
}
//cout << outputString << endl;
for(int i = 0; i < MAX_LENGTH; i++) //把修改完的都丟到input裡面 (我都從input當中索引) 這樣也不用開太多陣列 就只是有點複雜
{
inputString[i] = outputString[i];
}
checkPointers = inputString;//重置
outputString[0] = '\0';//把輸出陣列歸0
for(int i = 0; i < MAX_LENGTH; i++)//碰到比較正常的標點符號後面就留白
{
if(inputString[i] == ',' || inputString[i] == '!' || inputString[i] == '.')//再來就是來檢查沒有任何奇怪條件的標點符號
{
strncat(outputString, checkPointers, &inputString[i + 1] - checkPointers);//都在它們後面留一格空格
for(int j = 0; j < MAX_LENGTH; j++)
{
if(outputString[j] == '\0')
{
outputString[j] = ' ';
outputString[j + 1] = '\0';
break;
}
}
checkPointers = &inputString[i+1];
}
else if(inputString[i + 1] == '\0')
{
strncat(outputString, checkPointers, &inputString[i + 1] - checkPointers);
break;
}
}
//cout << outputString << endl;
for(int i = 0; i < MAX_LENGTH; i++) //把修改完的都丟到input裡面 (我都從input當中索引) 這樣也不用開太多陣列 就只是有點複雜
{
inputString[i] = outputString[i];
}
checkPointers = inputString;//重置
outputString[0] = '\0';//把輸出陣列歸0
for(int i = 0; i < MAX_LENGTH; i++)
{
if(isalnum(inputString[i]) != 0 && inputString[i + 1] == '(')//再來這個就是檢查左括號的段落了有左括弧就在她左邊留空格
{
strncat(outputString, checkPointers, &inputString[i + 1] - checkPointers);
for(int j = 0; j < MAX_LENGTH; j++)
{
if(outputString[j] == '\0')
{
outputString[j] = ' ';
outputString[j + 1] = '\0';
break;
}
}
checkPointers = &inputString[i+1];
}
else if(inputString[i + 1] == '\0')
{
strncat(outputString, checkPointers, &inputString[i + 1] - checkPointers);
break;
}
}
//cout << outputString << endl;
for(int i = 0; i < MAX_LENGTH; i++) //把修改完的都丟到input裡面 (我都從input當中索引) 這樣也不用開太多陣列 就只是有點複雜
{
inputString[i] = outputString[i];
}
checkPointers = inputString;//重置
outputString[0] = '\0';//把輸出陣列歸0
for(int i = 0; i < MAX_LENGTH; i++)
{
if(inputString[i] == ')' && ispunct(inputString[i + 1]) == 0)//如果右括號旁邊不是標點符號的話 那他的右邊也要多一格空格
{
strncat(outputString, checkPointers, &inputString[i + 1] - checkPointers);
for(int j = 0; j < MAX_LENGTH; j++)
{
if(outputString[j] == '\0')
{
outputString[j] = ' ';
outputString[j + 1] = '\0';
break;
}
}
checkPointers = &inputString[i+1];
}
else if(inputString[i + 1] == '\0')
{
strncat(outputString, checkPointers, &inputString[i + 1] - checkPointers);
break;
}
}
for(int i = 0; i < MAX_LENGTH; i++)//如果原本的字串縮了太多的話那就會多印一些莫名其妙的東西 所以有任何會印奇怪的東西的條件都要去除掉 讓他提早結束就能印出符合需求的程式就完成ㄌ
{
if(outputString[i] == ' ' && outputString[i + 1] == ' ')
{
outputString[i + 1] = '\0';
break;
}
}
cout << outputString << endl;
return 0;
}