2021年5月19日 星期三

C/C++ 依照特定格式 讀取檔案並 切割字串

C/C++ 依照特定格式 讀取檔案並 切割字串

tags: 部落格文章

這個新手大概很常用到,每次要用都google半天。這篇是把這些常用的函式封裝成一個物件,直接解決痛點方便操作。

因為是用 C++ 17 寫的,刷題提交用的代碼可能用不上,網站未必支援。簡單的讀檔可以參考這邊兩篇站內文。

讀取檔案

讀檔的問題參照上面兩篇就可以解決,這邊就概略貼上代碼就好

// 逐行讀取
vector<string> ReadFile_line(const string file_name) {
    vector<string> v;
    fstream fs(file_name, ios::in);
    if (!fs.is_open())
        throw runtime_error("Reading error.");
    for (string str; getline(fs, str);)
        v.emplace_back(str);
    return v;
}



切割字串

傳統的C字串處理可以這樣寫

#include <string.h>
void stringSplit(char* str, const char* delim) {
    char temp[64];
    strcpy(temp, str);

    char* pch = strtok(temp, delim);
    while (pch != NULL) {
        printf("%s\n", pch);
        pch = strtok(NULL, delim);
    }
}

C++ 11 可以這樣寫

#include <string>
void split(const string& s, vector<string>& tokens,
    const string& delimiters = " ")
{
    string::size_type lastPos = s.find_first_not_of(delimiters, 0);
    string::size_type pos = s.find_first_of(delimiters, lastPos);
    while (string::npos != pos || string::npos != lastPos) {
        tokens.push_back(s.substr(lastPos, pos - lastPos));
        lastPos = s.find_first_not_of(delimiters, pos);
        pos = s.find_first_of(delimiters, lastPos);
    }
}

C++17 可以更有效率的這樣寫

#include <string_view>
vector<string_view> splitSV(string_view strv, string_view delims = " ") {
    vector<string_view> output;
    for (size_t first = 0; first < strv.size();) {
        const auto second = strv.find_first_of(delims, first);
        if (first != second)
            output.emplace_back(strv.substr(first, second - first));
        if (second == string_view::npos)
            break;
        first = second + 1;
    }
    return output;
}

透過這樣的方式,就能夠把字串依照特定格式給切出來了。



封裝物件

切割完畢之後就用封裝拉,一般就是用 vector<string> 封裝,想要效率更高一點可以使用 vector<string_view>

因為有點長就貼到gist上了

封裝好的物件怎麼使用有一併寫在檔案底下的test函式裡

下面就簡單說明一下,最簡單的切割

string str = "123 | 321";
OneLine line(str, " | ");
cout << line << endl;

vector<string_view>&& tokenList = line;
for (size_t i = 0; i < tokenList.size(); i++)
    cout << tokenList[i] << endl;

物件本身返回的是一個 vector
這就意味了著在for裡面可以透過 line[idx] 來讀取被切割的字串

如果要從檔案讀取可以使用 openFile()

OneLine line;
line.openFile("a.txt");
while (line.getline()) {
    vector<string_view>&& tokenList = line;
    cout << tokenList << endl;
}

此時獲取的 tokenList 就可以用下標取出個別的字串了。



參考

Win10/11 變更使用者目錄的路徑 (中文改英文)

Win10/11 變更使用者目錄的路徑 (中文改英文)

tags: 部落格文章

怕過程出錯影響到使用者資料,可以先先創建第二個中文姓名的使用者充當白老鼠試驗,避免出什麼狀況。這不是必須的,不想弄第二次就直接用本尊來吧。

創建好之後記得先登入一次,不然使用者資料是空的還沒初始化




獲取使用者UID

先用要更改的使用者,打開終端機輸入以下命令獲取UID信息
(打開終端機方法:按下 Win+X 然後再按 A。或是直接搜尋Powershell打開)

[Security.Principal.WindowsIdentity]::GetCurrent().User.Value

會得到一串數字,把結尾幾位數記下來等一下會用到。




登入第二個管理員使用者

同一個帳號無法在檔案執行中修改目錄名稱,需要第二個普通管理員使用者來操作。如果電腦上沒有第二個使用者可以暫時打開超級管理,設定完後要刪除比較方便。


1. 打開超級管理員

先按下 Win+X 然後再按下 A ➔ 打開終端機,接著再輸入以下的代碼

net user "Administrator" /active:yes

2. 然後重新啟動電腦,選擇使用Administor(超級管理員)帳號登入

* 如果你的電腦重啟後自動登入原本的使用者。請記得登出後再選 Administor 登入



變更帳號路徑

再來進入超級管理員帳號就有權限可以做事情了


1. 打開登錄檔編輯器 (在開始搜尋 regedit 可以找到)




2. 找到下面這條路徑 (可以像資料夾那樣直接貼在上方快速到達)

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Profilelist



3. 修改登錄檔與資料夾名稱

這邊會看到很多資料夾 S-1-XXXX 這種的

  • 其中一個是你的使用者文件,剛剛有把數字記下來就直接對照就好
  • 沒有記下來就一個一個點進去,點到有熟悉的中文路徑就是對了


裡面可以看到一個文件是 ProfileImagePath 這個就是資料夾所在位置了。

  1. 登錄檔管理器中雙擊 ProfileImagePath 確認資料夾名稱


  2. 打開檔案總管,上方路徑貼上 C:\Users 並按下 Enter 前往該路徑


  3. 變更使用者文件的資料夾名字


  4. 雙擊進入變更後的使用者文件,並從上方複製路徑


  5. 回登錄檔管理器,把變更後的路徑貼回 ProfileImagePath 項目上


請務必使用複製貼上的方式更新路徑。



4. 確保萬無一失再重啟

重開前務必確保以下項目

  1. 使用者資料夾改名了
  2. 登錄檔 ProfileImagePath 的數值改了
  3. 上面兩個路徑是吻合的


再來重新啟動電腦,並登入變更後帳號即可。

* 以上只是改路徑,使用者名稱還是原來的使用者名稱沒有變的。



5. 關閉超級管理員

確保能正常登入後就可以把超級管理員關掉了,執行以下的代碼關閉。
net user "Administrator" /active:no







2021年5月12日 星期三

2021-05-12 PowerShell 修改檔案日期與時間 (1)

PowerShell 修改檔案日期與時間 (1)

tags: 部落格文章


新文章有更易用的方式詳細請看這篇



關於檔案的 修改時間 和 存取時間有什麼差別可以看這篇站內文


字串格式和日期格式怎麼互轉可以參考這一邊


修改檔案時間

其實也就是讀檔然後修改而已。

$Date = New-Object DateTime(2021, 12, 31, 18, 30, 59);
$FileName = "Z:\a.txt"

$file = Get-Item $FileName
$file.CreationTime   = $Date; #建立日期
$file.LastWriteTime  = $Date; #修改日期
$file.LastAccessTime = $Date; #存取日期

懶人包程式

這是封裝好的程式,要使用的話按下 Win+X 在按 A 會跳出一個可以輸入的視窗,把底下全部貼上。

# 產生日期格式
function NewDatetime {
    param (
        [string]$date = "",
        [string]$formatType = "yyyy-MM-dd HH:mm:ss"
    )
    # 未輸入日期則返回當前時間
    if ([string]::IsNullOrEmpty($date)) {
        $newDate = (Get-Date)
    }
    # 格式化日期
    else {
        $newDate = [DateTime]::ParseExact(
            $date.Trim(), $formatType,
            [CultureInfo]::InvariantCulture
        )
    }
    return $newDate
}
# 讀取檔案日期
function readFileDate {
    param (
        [string]$FileName
    )
    $file = Get-Item $FileName;
    Write-Host "建立日期" $file.CreationTime;     #建立日期
    Write-Host "修改日期" $file.LastWriteTime;    #修改日期
    Write-Host "存取日期" $file.LastAccessTime;   #存取日期
}
# 改變檔案日期
function ChangeFileDate {
    param (
        # [Parameter(Mandatory, Position=0)]
        [Parameter(Mandatory, Position=0)]
            [string]$FileName,
        [Parameter(ParameterSetName="setDetail")]
            [datetime]$CreationTime,
        [Parameter(ParameterSetName="setDetail")]
            [datetime]$LastWriteTime,
        [Parameter(ParameterSetName="setDetail")]
            [datetime]$LastAccessTime,
        [Parameter(ParameterSetName="setAll")]
            [datetime]$AllTime,
        [switch]$Preview
    )
    if ($AllTime) {
        $CreationTime   = $AllTime;
        $LastWriteTime  = $AllTime;
        $LastAccessTime = $AllTime;
    }

    $file = Get-Item $FileName
    if ($Preview) {
        Write-Host "[$FileName]"
        Write-Host "  " $file.CreationTime "-->" $CreationTime
        Write-Host "  " $file.LastWriteTime "-->" $LastWriteTime
        Write-Host  "  " $file.LastAccessTime "-->" $LastAccessTime
    } else {
        if ($CreationTime) {
            $file.CreationTime = $CreationTime; #建立日期
        } if ($LastWriteTime) {
            $file.LastWriteTime = $LastWriteTime; #修改日期
        } if ($LastAccessTime) {
            $file.LastAccessTime = $LastAccessTime; #存取日期
        }
    }
}

全部貼上去之後按 Enter 就可以開始使用了



使用方法

在使用前先執行這兩行代碼(記得要按Ennter輸入)
會自動切換到桌面,並建一個檔案等一下要範例用

cd ~\Desktop
"" >> a.txt

好了就可以開始拉

查詢檔案日期

readFileDate a.txt

修改全部日期

ChangeFileDate "a.txt" -AllTime "2021-5-10 23:59:59"

改完之後按 ↑ 兩次選到剛剛執行查詢的代碼,可以看一下有沒有改變

修改單一日期

如果只想改變其中一個而已的話,改法像這樣

# 只改變建立日期
ChangeFileDate "a.txt" -CreationTime "2021-5-11 23:59:59"
# 只改變修改日期
ChangeFileDate "a.txt" -LastWriteTime "2021-5-12 23:59:59"
# 只改變存取日期
ChangeFileDate "a.txt" -LastAccessTime "2021-5-13 23:59:59"

如果要改其中兩個,可以打兩行也可以把後面的部分串起來就好

# 改任意兩個(這3組可以隨便串)
ChangeFileDate "a.txt" -CreationTime "2021-5-14 23:59:59" -LastAccessTime "2021-5-15 23:59:59"

預覽

如果你怕改錯的話可以在加上 -Preview 預覽一下
加上這個之後就不會變更日期,只會看到預覽的訊息

ChangeFileDate "a.txt" -AllTime "2021-5-10 23:59:59" -Preview

PowerShell 字串String 與 日期Datetime 格式轉換

PowerShell 字串String 與 日期Datetime 格式轉換

tags: 部落格文章

字串轉時間

型態的顯式轉換 (僅限英文AM/PM)

[datetime]"2025/02/04 AM 11:59"
[datetime]"2025/02/04 23:59"
[datetime]"2025/02/04"
[datetime]"2025-2-4"


物件建構子

New-Object DateTime(2021, 5, 12, 22, 29, 30)




進階自訂格式

核心的程式長這樣

[DateTime]::ParseExact("13.May.2017", "dd.MMM.yyyy",[CultureInfo]::InvariantCulture)

這樣簡單一行就能夠格式化字串到日期了

強化一下寫好的副程式是這樣的

function newDatetime {
    param (
        [string]$date = "",
        [string]$formatType = "yyyy-MM-dd HH:mm:ss"
    )
    # 未輸入日期則返回當前時間
    if ([string]::IsNullOrEmpty($date)) {
        $newDate = (Get-Date)
    }
    # 格式化日期
    else {
        $newDate = [DateTime]::ParseExact(
            $date.Trim(), $formatType,
            [CultureInfo]::InvariantCulture
        )
    }
    return $newDate
}

使用的話直接這就可以用了

newDatetime "2000-01-01 12:00:00"

要自訂格式的話,後面空格多補一個參數

newDatetime "13.May.2017" "dd.MMM.yyyy"





日期轉字串

再來是把日期轉出來到字串,這個就比較容易

方式1

直接轉成字串即可

(Get-Date).ToString("yyyy-MM-dd HH:mm:ss")

方式2

陣列轉換

'{0:yyyy-MM-dd HH:mm:ss}' -f (Get-Date)

Win10 【修改日期】和【存取日期】有什麼差別不同處

Win10 【修改日期】和【存取日期】有什麼差別不同處

tags: 部落格文章

以前就一直很好奇這兩個東西到底有什麼不同,因為邏輯很奇怪,有比對過的人應該都會滿頭問號XDD

今天寫程式要改日期,不得不把他們弄懂只好乖乖爬文了,遺憾的目前能檢索到的中文資料居然沒一篇講清楚的,來補一下這個中文資源吧~


如何任意改變檔案的時間可以參考這篇文
CHG: 2025-02-04 PowerShell 修改檔案日期與時間 (3)




建立日期 CreationTime

這個應該很好懂就是這一份檔案什麼時產出來的,這個永遠都不會變動。

以下情況才會發生改變

  1. 複製的時候的時候,產生一份新檔案(修改日期會保留)
  2. 上傳到雲端在下載回來的檔案屬於新建檔案(通常修改會滯後於新建,時間差就是下載的時間)
  3. RAR解壓出來屬於複製檔案



修改日期 LastWriteTime

指的是對檔案的內容的變更,這個應該沒什麼疑念。
只要有修改內容就會更新時間了。



存取日期 LastAccessTime

這個才是最難理解的,看名字就覺得開啟檔案也算吧,很遺憾不一定會馬上反應。

這不是非常反邏輯不是就寫著存取了嗎?

事實上因為每次開檔就更改存取日期非常消耗系統效能,預設微軟把她關了
對就是給關了,但並不是完全關閉而是智能保護

這個智能保護的邏輯可能隨著Windows系統更新被優化,當前測試版本是Win10 20H2

怎麼解除保護狀態呢,很簡單直接打開記事本給他修改一下後保存,就解除了

當保護解除時,以下動作都會變動存取日期

  1. 查看檔案內容 (寫到緩存還沒更新到物理檔案)
  2. 檔案內容修改
  3. 檔名修改
  4. 移動檔案
  5. 複製檔案

基本上就是名如其實,有存取都會紀錄

至於怎查看緩存的內容可以直接打下面這行指令

# 查看檔案存取日期
(Get-Item "Z:\a.txt").LastAccessTime


如何取消能保護可以執行這行指令
(沒需求的話別做死浪費硬碟效能)

# 關閉智能保護
# fsutil behavior set disablelastaccess 0

另外有一種情況開檔會變更”存取日期”,但不會變更”修改日期”,有些Excle或Word裡面是有帶腳本的的打開的瞬間腳本執行就會變更”存取日期”和”修改日期”,關閉檔案後因為沒變更軟體會自動把”修改日期”改回原本的日期。以至於打開又關閉一看,奇怪怎麼存取日期變了。





從日期判斷檔案有過什麼操作

實際做一些操作來試試看變化吧

更改檔名(未解除保護)

沒有變動

建立日期 2021/5/12 下午 05:32:57
修改日期 2021/5/12 下午 05:32:57
存取日期 2021/5/12 下午 05:32:57

移動檔案(未解除保護)

沒有變動

建立日期 2021/5/12 下午 05:27:29
修改日期 2021/5/12 下午 05:27:29
存取日期 2021/5/12 下午 05:27:29

複製檔案

建立與存取日期會更新

建立日期 2021/5/12 下午 05:26:32
修改日期 2021/5/15 下午 12:34:56
存取日期 2021/5/12 下午 05:26:32

修改內容

修改會滯後於修改(這段時間是你開檔到存檔的時間差)

建立日期 2021/5/12 下午 05:59:07
修改日期 2021/5/12 下午 05:59:36
存取日期 2021/5/12 下午 05:59:38





參考

2021年5月2日 星期日

chrome瀏覽器 開某些網站會 LAG 改用 EDGE 就好了怎麼處理

chrome瀏覽器 開某些網站會 LAG 改用 EDGE 就好了怎麼處理

這個問題我一直很好奇怎麼會這樣,我開Youtube、FaceBook都可以感受到。

尤其是舊版的FB卡的不要不要的,甚至是HackMD這種筆記網頁也會,後來在巴哈看到有人在討論的意外地解決了。

解決辦法

來這個頁面

chrome://flags/#use-angle

把Choose ANGLE graphics backend這個選項改成 D3D9 可以改善。
具體原理也不太清楚,貌似是和顯示卡有關吧~

個人是直接改用 Edge 棄用 chrome 了